<# Update-MozillaFirefox.ps1 Requires either (a) PowerShell v3 or later or (b) .NET 3.5 or later (at Step 8: JSON import and conversion). Assumes that one instance (the latest non-beta version) of Mozilla Firefox is to be used. The script will exit at Step 15, if more than one instance of Firefox is detected. Latest Firefox version numbers: https://product-details.mozilla.org/ https://product-details.mozilla.org/1.0/firefox_versions.json https://product-details.mozilla.org/1.0/thunderbird_versions.json Languages: https://product-details.mozilla.org/1.0/languages.json Regions: https://product-details.mozilla.org/1.0/regions/en-US.json Release History: https://product-details.mozilla.org/1.0/firefox_history_stability_releases.json Download Latest Firefox Version URLs: https://ftp.mozilla.org/pub/firefox/releases/latest/README.txt https://download.mozilla.org/?product=firefox-latest&os=win&lang=en-US http://www.mozilla.org/firefox/organizations/all/ https://www.mozilla.org/en-US/firefox/all/ Check if the installed version of Firefox is the latest: https://www.mozilla.org/en-US/firefox/new/ Uninstall Firefox: https://support.mozilla.org/en-US/kb/uninstall-firefox-from-your-computer https://wiki.mozilla.org/Installer:Command_Line_Arguments #> # Step 1 # Establish the common parameters $path = $env:temp $computer = $env:COMPUTERNAME $ErrorActionPreference = "Stop" $start_time = Get-Date $empty_line = "" $quote ='"' $unquote ='"' $firefox_enumeration = @() $latest_firefox = @() $after_update_firefoxes = @() # Function to check whether a program is installed or not Function Check-InstalledSoftware ($display_name) { Return Get-ItemProperty $registry_paths -ErrorAction SilentlyContinue | Where-Object { $_.DisplayName -like $display_name } } # function # Step 2 # Determine the architecture of a machine # Credit: Tobias Weltner: "PowerTips Monthly vol 8 January 2014" If ([IntPtr]::Size -eq 8) { $empty_line | Out-String "Running in a 64-bit subsystem" | Out-String $64 = $true $bit_number = "64" $registry_paths = @( 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*', 'HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*' ) $empty_line | Out-String } Else { $empty_line | Out-String "Running in a 32-bit subsystem" | Out-String $64 = $false $bit_number = "32" $registry_paths = @( 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*' ) $empty_line | Out-String } # Else # Step 3 # Determine whether Firefox is installed or not $firefox_is_installed = $false If ((Check-InstalledSoftware "*Firefox*") -ne $null) { $firefox_is_installed = $true } Else { $continue = $true } # Else # Step 4 # Enumerate the existing installed Firefoxes $32_bit_firefox_is_installed = $false $64_bit_firefox_is_installed = $false $registry_paths_selection = Get-ItemProperty $registry_paths -ErrorAction SilentlyContinue | Where-Object { ($_.DisplayName -like "*Firefox*" ) -and ($_.Publisher -like "Mozilla*" )} If ($registry_paths_selection -ne $null) { ForEach ($item in $registry_paths_selection) { # Custom Values If (($item.DisplayName.Split(" ")[-1] -match "\(") -eq $false) { $locale = ($item.DisplayName.Split(" ")[-1]).Replace(")","") } Else { $continue = $true } # Else If (($item.DisplayName.Split(" ")[-1] -match "\(x") -eq $true) { If ($item.DisplayName.Split(" ")[-1] -like "(x86") { $32_bit_firefox_is_installed = $true $type = "32-bit" } ElseIf ($item.DisplayName.Split(" ")[-1] -like "(x64") { $64_bit_firefox_is_installed = $true $type = "64-bit" } Else { $continue = $true } # Else } ElseIf (($item.DisplayName.Split(" ")[-2] -match "\(x") -eq $true) { If ($item.DisplayName.Split(" ")[-2] -like "(x86") { $32_bit_firefox_is_installed = $true $type = "32-bit" } ElseIf ($item.DisplayName.Split(" ")[-2] -like "(x64") { $64_bit_firefox_is_installed = $true $type = "64-bit" } Else { $continue = $true } # Else } Else { $continue = $true } # Else # $product_version_enum = ((Get-ItemProperty -Path "C:\Program Files (x86)\Mozilla Firefox\Firefox.exe" -ErrorAction SilentlyContinue -Name VersionInfo).VersionInfo).ProductVersion $product_version_enum = ((Get-ItemProperty -Path "$($item.InstallLocation)\Firefox.exe" -ErrorAction SilentlyContinue -Name VersionInfo).VersionInfo).ProductVersion $test_stability = $product_version_enum -match "(\d+)\.(\d+)\.(\d+)" $test_major = $product_version_enum -match "(\d+)\.(\d+)" If (($product_version_enum -ne $null) -and ($test_stability -eq $true)) { $product_version_enum -match "(?\d+)\.(?\d+)\.(?\d+)" | Out-Null } Else { $continue = $true } If (($product_version_enum -ne $null) -and ($test_stability -eq $false) -and ($test_major -eq $true)) { $product_version_enum -match "(?\d+)\.(?\d+)" | Out-Null } Else { $continue = $true } $firefox_enumeration += $obj_firefox = New-Object -TypeName PSCustomObject -Property @{ 'Name' = $item.DisplayName.Replace("(TM)","") 'Publisher' = $item.Publisher 'Product' = $item.DisplayName.Split(" ")[1] 'Type' = $type 'Locale' = $locale 'Major Version' = If ($Matches.C1 -ne $null) { $Matches.C1 } Else { $continue = $true } 'Minor Version' = If ($Matches.C2 -ne $null) { $Matches.C2 } Else { $continue = $true } 'Build Number' = If ($Matches.C3 -ne $null) { $Matches.C3 } Else { "-" } 'Computer' = $computer 'Install Location' = $item.InstallLocation 'Standard Uninstall String' = $item.UninstallString.Trim('"') 'Release Notes' = $item.URLUpdateInfo 'Identifying Number' = $item.PSChildName 'Version' = $item.DisplayVersion } # New-Object } # foreach ($item) # Display the Firefox Version Enumeration in console If ($firefox_enumeration -ne $null) { $firefox_enumeration.PSObject.TypeNames.Insert(0,"Firefox Version Enumeration") $firefox_enumeration_selection = $firefox_enumeration | Select-Object 'Name','Publisher','Product','Type','Locale','Major Version','Minor Version','Build Number','Computer','Install Location','Standard Uninstall String','Release Notes','Version' $empty_line | Out-String $header_firefox_enumeration = "Enumeration of Firefox Versions Found on the System" $coline_firefox_enumeration = "---------------------------------------------------" Write-Output $header_firefox_enumeration $coline_firefox_enumeration | Out-String Write-Output $firefox_enumeration_selection } Else { $continue = $true } # Else } Else { $continue = $true } # Else (Step 4) # Step 5 # Warn the user if more than one instance of Firefox is installed on the system $multiple_firefoxes = $false If ((($firefox_enumeration | Measure-Object Name).Count) -eq 0) { Write-Verbose "No Firefox seems to be installed on the system." } ElseIf ((($firefox_enumeration | Measure-Object Name).Count) -eq 1) { # One instance of Firefox seems to be installed. $continue = $true } ElseIf ((($firefox_enumeration | Measure-Object Name).Count) -ge 2) { $empty_line | Out-String Write-Warning "More than one instance of Firefox seems to be installed on the system." $multiple_firefoxes = $true } Else { $continue = $true } # Else # Step 6 # Check if the computer is connected to the Internet # Credit: ps1: "Test Internet connection" If (([Activator]::CreateInstance([Type]::GetTypeFromCLSID([Guid]'{DCB00C01-570F-4A9B-8D69-199FDBA5723B}')).IsConnectedToInternet) -eq $false) { $empty_line | Out-String Return "The Internet connection doesn't seem to be working. Exiting without checking the latest Firefox version numbers or without updating Firefox (at Step 6)." } Else { Write-Verbose 'Checking the most recent Firefox version numbers from the Mozilla website...' } # Else # Step 7 # Check the baseline Firefox version numbers by connecting to the Mozilla website and write it to a file (The Baseline). Also download three additional auxillary JSON files from Mozilla. # Source: https://groups.google.com/forum/#!topic/mozilla.release.engineering/EOyvryJNq7A $baseline_url = "https://product-details.mozilla.org/1.0/firefox_versions.json" $baseline_file = "$path\firefox_current_versions.json" try { $download_baseline = New-Object System.Net.WebClient $download_baseline.DownloadFile($baseline_url, $baseline_file) } catch [System.Net.WebException] { Write-Warning "Failed to access $baseline_url" If (([Activator]::CreateInstance([Type]::GetTypeFromCLSID([Guid]'{DCB00C01-570F-4A9B-8D69-199FDBA5723B}')).IsConnectedToInternet) -eq $true) { $page_exception_text = "Please consider running this script again. Sometimes this Mozilla page just isn't queryable for no apparent reason. The success rate 'in the second go' usually seems to be a bit higher." $empty_line | Out-String Write-Output $page_exception_text } Else { $continue = $true } # Else $empty_line | Out-String Return "Exiting without checking the latest Firefox version numbers or without updating Firefox (at Step 7)." } $history_url = "https://product-details.mozilla.org/1.0/firefox_history_stability_releases.json" $history_file = "$path\firefox_release_history.json" try { $download_history = New-Object System.Net.WebClient $download_history.DownloadFile($history_url, $history_file) } catch [System.Net.WebException] { Write-Warning "Failed to access $history_url" If (([Activator]::CreateInstance([Type]::GetTypeFromCLSID([Guid]'{DCB00C01-570F-4A9B-8D69-199FDBA5723B}')).IsConnectedToInternet) -eq $true) { $empty_line | Out-String Write-Output $page_exception_text } Else { $continue = $true } # Else $empty_line | Out-String Return "Exiting without checking the latest Firefox version numbers or without updating Firefox (at Step 7 while trying to download the history file)." } # https://product-details.mozilla.org/1.0/all.json # https://product-details.mozilla.org/1.0/firefox.json $major_url = "https://product-details.mozilla.org/1.0/firefox_history_major_releases.json" $major_file = "$path\firefox_major_versions.json" try { $download_major = New-Object System.Net.WebClient $download_major.DownloadFile($major_url, $major_file) } catch [System.Net.WebException] { Write-Warning "Failed to access $major_url" If (([Activator]::CreateInstance([Type]::GetTypeFromCLSID([Guid]'{DCB00C01-570F-4A9B-8D69-199FDBA5723B}')).IsConnectedToInternet) -eq $true) { $empty_line | Out-String Write-Output $page_exception_text } Else { $continue = $true } # Else $empty_line | Out-String Return "Exiting without checking the latest Firefox version numbers or without updating Firefox (at Step 7 while trying to download a file containing the major version release dates)." } $language_url = "https://product-details.mozilla.org/1.0/languages.json" $language_file = "$path\firefox_languages.json" try { $download_language = New-Object System.Net.WebClient $download_language.DownloadFile($language_url, $language_file) } catch [System.Net.WebException] { Write-Warning "Failed to access $language_url" If (([Activator]::CreateInstance([Type]::GetTypeFromCLSID([Guid]'{DCB00C01-570F-4A9B-8D69-199FDBA5723B}')).IsConnectedToInternet) -eq $true) { $empty_line | Out-String Write-Output $page_exception_text } Else { $continue = $true } # Else $empty_line | Out-String Return "Exiting without checking the latest Firefox version numbers or without updating Firefox (at Step 7 while trying to download the languages file)." } $region_url = "https://product-details.mozilla.org/1.0/regions/en-US.json" $region_file = "$path\firefox_regions.json" try { $download_region = New-Object System.Net.WebClient $download_region.DownloadFile($region_url, $region_file) } catch [System.Net.WebException] { Write-Warning "Failed to access $region_url" If (([Activator]::CreateInstance([Type]::GetTypeFromCLSID([Guid]'{DCB00C01-570F-4A9B-8D69-199FDBA5723B}')).IsConnectedToInternet) -eq $true) { $empty_line | Out-String Write-Output $page_exception_text } Else { $continue = $true } # Else $empty_line | Out-String Return "Exiting without checking the latest Firefox version numbers or without updating Firefox (at Step 7 while trying to download the regions file)." } Start-Sleep -Seconds 2 # Step 8 # Import the downloaded JSON files as objects # Source: http://stackoverflow.com/questions/1825585/determine-installed-powershell-version?rq=1 # Source: https://msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powershell.utility/convertfrom-json # Source: https://blogs.technet.microsoft.com/heyscriptingguy/2014/04/23/powertip-convert-json-file-to-powershell-object/ # Source: http://powershelldistrict.com/powershell-json/ # Source: https://technet.microsoft.com/en-us/library/ee692803.aspx # Source: http://stackoverflow.com/questions/32887583/powershell-v2-converts-dictionary-to-array-when-returned-from-a-function <# Update channels - Advanced Updates can be retrieved from a number of different update channels. To check which channel you are on, look in about:config at app.update.channel. This determines what kind of updates you will receive. The current update channels are: nightly: The nightly channel allows you to update to every nightly test build that is produced. There are nightly channels for the trunk (i.e., current release version plus 3 numbers); this is also a nightly channel for the remaining legacy branches (Firefox 3.6 & Thunderbird 3.1 builds). aurora: This is a new channel which has been introduced with the rapid-release scheme; these builds reflect changes which also went into beta for the next release, thus making them available immediately, or which were deemed unsuitable for beta but safe for the following release (and, in general don't contain any string changes). beta: The beta channel lets you receive every beta, release candidate, and release version of the product (e.g. Firefox 1.5 beta 1, Firefox 1.5 RC 1, Firefox 1.5, etc.). With the new rapid-release process (starting with Firefox/Thunderbird 5.0 and SeaMonkey 2.1), every beta is a release candidate for the next version now, and the actual release build is no longer provided on the beta channel. esr: This is a special release channel for extended-support releases which are mostly targeting enterprise users. Features are frozen with every 7th or so update cycle and only security updates provided (i.e., Firefox/Thunderbird 10.0 ESR updates to 10.0.1, 10.0.2, ..., 10.0.x, then 17.0 as the next ESR branch). default: This channel is used when there is no channel information, for example if you build Firefox or Thunderbird yourself. There are no updates on this channel. This channel is frequently used by Linux distributions, given that they provide own updates through their respective package-management system. release: The release channel will provide stable release versions, including security updates (e.g. Firefox 2.0, 2.0.0.4 etc.). Source: http://kb.mozillazine.org/Software_Update #> # Join the two files containing release dates # Source: https://msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powershell.utility/convertfrom-stringdata # Source: https://technet.microsoft.com/en-us/library/ee692803.aspx # $history_file_content = (Get-Content -Path $history_file) # $major_file_content = (Get-Content -Path $major_file) $history_conversion = [System.IO.File]::ReadAllText($history_file).Replace("}",", ") $major_conversion = [System.IO.File]::ReadAllText($major_file).Replace("{","") $all_firefox = [string]$history_conversion + $major_conversion If ((($PSVersionTable.PSVersion).Major -lt 3) -or (($PSVersionTable.PSVersion).Major -eq $null)) { # PowerShell v2 or earlier JSON import # Credit: Goyuix: "Read Json Object in Powershell 2.0" # Requires .NET 3.5 or later $powershell_v2_or_earlier = $true If (($PSVersionTable.PSVersion).Major -eq $null) { $powershell_v1 = $true # LoadWithPartialName is obsolete, source: https://msdn.microsoft.com/en-us/library/system.reflection.assembly(v=vs.110).aspx [System.Reflection.Assembly]::LoadWithPartialName("System.Web.Extensions") } ElseIf (($PSVersionTable.PSVersion).Major -lt 3) { $powershell_v2 = $true Add-Type -AssemblyName "System.Web.Extensions" } Else { $continue = $true } # Else $serializer = New-Object System.Web.Script.Serialization.JavaScriptSerializer $latest = $serializer.DeserializeObject((Get-Content -Path $baseline_file) -join "`n") $history = $serializer.DeserializeObject((Get-Content -Path $history_file) -join "`n") $major = $serializer.DeserializeObject((Get-Content -Path $major_file) -join "`n") $all_dates = $serializer.DeserializeObject(($all_firefox) -join "`n") $language = $serializer.DeserializeObject((Get-Content -Path $language_file) -join "`n") $region = $serializer.DeserializeObject((Get-Content -Path $region_file) -join "`n") try { $latest_release_date = (Get-Date ($all_dates.Get_Item("$($latest.LATEST_FIREFOX_VERSION)"))).ToShortDateString() } catch { $message = $error[0].Exception Write-Verbose $message } } ElseIf (($PSVersionTable.PSVersion).Major -ge 3) { # PowerShell v3 or later JSON import $latest = (Get-Content -Raw -Path $baseline_file) | ConvertFrom-Json $history = (Get-Content -Raw -Path $history_file) | ConvertFrom-Json $major = (Get-Content -Raw -Path $major_file) | ConvertFrom-Json $all_dates = ($all_firefox) | ConvertFrom-Json $language = (Get-Content -Raw -Path $language_file) | ConvertFrom-Json $region = (Get-Content -Raw -Path $region_file) | ConvertFrom-Json try { $latest_release_date = (Get-Date ($all_dates | Select-Object -ExpandProperty "$($latest.LATEST_FIREFOX_VERSION)")).ToShortDateString() } catch { $message = $error[0].Exception Write-Verbose $message } } Else { $continue = $true } # Else # Had the release date not yet been resolved, convert the .json formatted dates to a hash table and try to figure out the date # Source: https://msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powershell.utility/convertfrom-stringdata # Source: https://technet.microsoft.com/en-us/library/ee692803.aspx If ($latest_release_date -eq $null) { $raw_conversion = $all_firefox.Replace("{","").Replace(": "," = ").Replace(",","`r`n").Replace("}","`r`n").Replace('"','') $release_dates = ConvertFrom-StringData -StringData $raw_conversion $release_dates_list = $release_dates.GetEnumerator() | Sort-Object Value -Descending If ($release_dates.ContainsKey("$($latest.LATEST_FIREFOX_VERSION)")) { $latest_release_date = $release_dates.Get_Item("$($latest.LATEST_FIREFOX_VERSION)") } Else { $latest_release_date = "[unknown]" } # Else } Else { $continue = $true } # Else $latest_firefox += $obj_latest = New-Object -TypeName PSCustomObject -Property @{ 'Nightly' = $latest.FIREFOX_NIGHTLY 'Aurora' = $latest.FIREFOX_AURORA 'In Development' = $latest.LATEST_FIREFOX_DEVEL_VERSION 'Released Beta' = $latest.LATEST_FIREFOX_RELEASED_DEVEL_VERSION 'Extended-Support Release (ESR)' = $latest.FIREFOX_ESR 'Extended-Support Release (ESR) Next' = $latest.FIREFOX_ESR_NEXT 'Old' = $latest.LATEST_FIREFOX_OLDER_VERSION 'Latest Release Date' = $latest_release_date 'Major Versions' = $major_url 'Release History' = $history_url 'History' = "https://www.mozilla.org/en-US/firefox/releases/" 'Info' = [string]"https://www.mozilla.org/en-US/firefox/" + $latest.LATEST_FIREFOX_VERSION + "/releasenotes/" 'Current' = $latest.LATEST_FIREFOX_VERSION } # New-Object $latest_firefox.PSObject.TypeNames.Insert(0,"Latest Firefox Versions") $most_recent_firefox_version = $latest_firefox | Select-Object -ExpandProperty Current # Display the most recent and extended support Firefox version numbers in console If ($latest_firefox -ne $null) { $latest_firefox_selection = $latest_firefox | Select-Object 'Nightly','Aurora','In Development','Released Beta','Extended-Support Release (ESR)','Old','Latest Release Date','Release History','History','Info','Current' $empty_line | Out-String $header_firefox_enumeration = "Latest Firefox Versions" $coline_firefox_enumeration = "-----------------------" Write-Output $header_firefox_enumeration $coline_firefox_enumeration | Out-String Write-Output $latest_firefox_selection } Else { $continue = $true } # Else # Step 9 # Try to determine which Firefox versions, if any, are outdated and need to be updated. $downloading_firefox_is_required = $false $downloading_firefox_32_is_required = $false $downloading_firefox_64_is_required = $false If ($firefox_is_installed -eq $true) { $most_recent_firefox_already_exists = Check-InstalledSoftware "Mozilla Firefox $($most_recent_firefox_version)*" $most_recent_32_bit_firefox_already_exists = Check-InstalledSoftware "Mozilla Firefox $($most_recent_firefox_version) (x86*" $most_recent_64_bit_firefox_already_exists = Check-InstalledSoftware "Mozilla Firefox $($most_recent_firefox_version) (x64*" $all_32_bit_firefoxes = $firefox_enumeration | Where-Object { $_.Type -eq "32-bit" } $number_of_32_bit_firefoxes = ($all_32_bit_firefoxes | Measure-Object).Count $all_64_bit_firefoxes = $firefox_enumeration | Where-Object { $_.Type -eq "64-bit" } $number_of_64_bit_firefoxes = ($all_64_bit_firefoxes | Measure-Object).Count # 32-bit If ($32_bit_firefox_is_installed -eq $false) { $continue = $true } ElseIf (($32_bit_firefox_is_installed -eq $true) -and ($most_recent_32_bit_firefox_already_exists) -and ($number_of_32_bit_firefoxes -eq 1)) { # $downloading_firefox_32_is_required = $false $locale = If (($most_recent_32_bit_firefox_already_exists.DisplayName.Split(" ")[-1] -match "\(") -eq $false) { If ($powershell_v2_or_earlier -eq $true) { $language.Get_Item(($most_recent_32_bit_firefox_already_exists.DisplayName.Split(" ")[-1]).Replace(")","")) } Else { $language | Select-Object -ExpandProperty (($most_recent_32_bit_firefox_already_exists.DisplayName.Split(" ")[-1]).Replace(")","")) } # Else } Else { $continue = $true } # Else ($locale) If ($powershell_v2_or_earlier -eq $true) { try { $release_date = $all_dates.Get_Item($most_recent_32_bit_firefox_already_exists.DisplayVersion) } catch { $message = $error[0].Exception Write-Verbose $message } } Else { try { $release_date = $all_dates | Select-Object -ExpandProperty $most_recent_32_bit_firefox_already_exists.DisplayVersion } catch { $message = $error[0].Exception Write-Verbose $message } } # Else $currently_installed_32 += New-Object -TypeName PSCustomObject -Property @{ 'Name' = $most_recent_32_bit_firefox_already_exists.DisplayName.replace("(TM)","") 'Publisher' = $most_recent_32_bit_firefox_already_exists.Publisher 'Product' = $most_recent_32_bit_firefox_already_exists.DisplayName.Split(" ")[1] 'Type' = "32-bit" 'Locale' = $locale 'Computer' = $computer 'Install Location' = $most_recent_32_bit_firefox_already_exists.InstallLocation 'Release Notes' = $most_recent_32_bit_firefox_already_exists.URLUpdateInfo 'Standard Uninstall String' = $most_recent_32_bit_firefox_already_exists.UninstallString.Trim('"') 'Identifying Number' = $most_recent_32_bit_firefox_already_exists.PSChildName 'Release_Date' = $release_date 'Version' = $most_recent_32_bit_firefox_already_exists.DisplayVersion } # New-Object $currently_installed_32.PSObject.TypeNames.Insert(0,"Existing Current Firefox 32-bit") $empty_line | Out-String Write-Output "Currently (until the next Firefox version is released) the $($($currently_installed_32.Locale).English) 32-bit $($currently_installed_32.Name) released on $((Get-Date ($currently_installed_32.Release_Date)).ToShortDateString()) doesn't need any further maintenance or care." } Else { $downloading_firefox_32_is_required = $true $downloading_firefox_is_required = $true ForEach ($32_bit_firefox in $all_32_bit_firefoxes) { If ($32_bit_firefox.Version -eq $most_recent_firefox_version) { If ($powershell_v2_or_earlier -eq $true) { try { $release_date = $all_dates.Get_Item($32_bit_firefox.Version) } catch { $message = $error[0].Exception Write-Verbose $message } } Else { try { $release_date_32 = $all_dates | Select-Object -ExpandProperty "$($32_bit_firefox.Version)" } catch { $message = $error[0].Exception Write-Verbose $message } } # Else $empty_line | Out-String Write-Output "Currently (until the next Firefox version is released) the 32-bit $($32_bit_firefox.Name) released on $((Get-Date ($release_date_32)).ToShortDateString()) doesn't need any further maintenance or care." } Else { $empty_line | Out-String Write-Warning "$($32_bit_firefox.Name) seems to be outdated." $empty_line | Out-String Write-Output "The most recent non-beta Firefox version is $most_recent_firefox_version. The installed 32-bit Firefox version $($32_bit_firefox.Version) needs to be updated." } # Else } # ForEach } # Else # 64-bit If ($64_bit_firefox_is_installed -eq $false) { $continue = $true } ElseIf (($64_bit_firefox_is_installed -eq $true) -and ($most_recent_64_bit_firefox_already_exists) -and ($number_of_64_bit_firefoxes -eq 1)) { # $downloading_firefox_64_is_required = $false $locale = If (($most_recent_64_bit_firefox_already_exists.DisplayName.Split(" ")[-1] -match "\(") -eq $false) { If ($powershell_v2_or_earlier -eq $true) { $language.Get_Item(($most_recent_64_bit_firefox_already_exists.DisplayName.Split(" ")[-1]).Replace(")","")) } Else { $language | Select-Object -ExpandProperty (($most_recent_64_bit_firefox_already_exists.DisplayName.Split(" ")[-1]).Replace(")","")) } # Else } Else { $continue = $true } # Else ($locale) If ($powershell_v2_or_earlier -eq $true) { try { $release_date = $all_dates.Get_Item($most_recent_64_bit_firefox_already_exists.DisplayVersion) } catch { $message = $error[0].Exception Write-Verbose $message } } Else { try { $release_date = $all_dates | Select-Object -ExpandProperty $most_recent_64_bit_firefox_already_exists.DisplayVersion } catch { $message = $error[0].Exception Write-Verbose $message } } # Else $currently_installed_64 += New-Object -TypeName PSCustomObject -Property @{ 'Name' = $most_recent_64_bit_firefox_already_exists.DisplayName.replace("(TM)","") 'Publisher' = $most_recent_64_bit_firefox_already_exists.Publisher 'Product' = $most_recent_64_bit_firefox_already_exists.DisplayName.Split(" ")[1] 'Type' = "64-bit" 'Locale' = $locale 'Computer' = $computer 'Install Location' = $most_recent_64_bit_firefox_already_exists.InstallLocation 'Release Notes' = $most_recent_64_bit_firefox_already_exists.URLUpdateInfo 'Standard Uninstall String' = $most_recent_64_bit_firefox_already_exists.UninstallString.Trim('"') 'Identifying Number' = $most_recent_64_bit_firefox_already_exists.PSChildName 'Release_Date' = $release_date 'Version' = $most_recent_64_bit_firefox_already_exists.DisplayVersion } # New-Object $currently_installed_64.PSObject.TypeNames.Insert(0,"Existing Current Firefox 64-bit") $empty_line | Out-String Write-Output "Currently (until the next Firefox version is released) the $($($currently_installed_64.Locale).English) 64-bit $($currently_installed_64.Name) released on $((Get-Date ($currently_installed_64.Release_Date)).ToShortDateString()) doesn't need any further maintenance or care." } Else { $downloading_firefox_64_is_required = $true $downloading_firefox_is_required = $true ForEach ($64_bit_firefox in $all_64_bit_firefoxes) { If ($64_bit_firefox.Version -eq $most_recent_firefox_version) { If ($powershell_v2_or_earlier -eq $true) { try { $release_date_64 = $all_dates.Get_Item($64_bit_firefox.Version) } catch { $message = $error[0].Exception Write-Verbose $message } } Else { try { $release_date_64 = $all_dates | Select-Object -ExpandProperty "$($64_bit_firefox.Version)" } catch { $message = $error[0].Exception Write-Verbose $message } } # Else $empty_line | Out-String Write-Output "Currently (until the next Firefox version is released) the 64-bit $($64_bit_firefox.Name) released on $((Get-Date ($release_date_64)).ToShortDateString()) doesn't need any further maintenance or care." } Else { $empty_line | Out-String Write-Warning "$($64_bit_firefox.Name) seems to be outdated." $empty_line | Out-String Write-Output "The most recent non-beta Firefox version is $most_recent_firefox_version. The installed 64-bit Firefox version $($64_bit_firefox.Version) needs to be updated." } # Else } # ForEach } # Else } Else { $continue = $true } # Else # Step 10 # Write the Maintenance info in console If ($firefox_is_installed -eq $true) { $32_bit_uninstall_string = $all_32_bit_firefoxes | Select-Object -ExpandProperty 'Standard Uninstall String' $64_bit_uninstall_string = $all_64_bit_firefoxes | Select-Object -ExpandProperty 'Standard Uninstall String' $obj_maintenance += New-Object -TypeName PSCustomObject -Property @{ 'Open the Firefox primary profile location' = [string]'Invoke-Item ' + $quote + [Environment]::GetFolderPath("ApplicationData") + '\Mozilla\Firefox\Profiles' + $unquote 'Open the Firefox secondary profile location' = [string]'Invoke-Item ' + $quote + [Environment]::GetFolderPath("LocalApplicationData") + '\Mozilla\Firefox\Profiles' + $unquote 'Open the updates.xml file location' = [string]'Invoke-Item ' + $quote + [Environment]::GetFolderPath("LocalApplicationData") + '\Mozilla\updates\' + $unquote 'Uninstall the 32-bit Firefox' = If ($32_bit_firefox_is_installed -eq $true) { $32_bit_uninstall_string } Else { [string]'[not installed]' } 'Uninstall the 64-bit Firefox' = If ($64_bit_firefox_is_installed -eq $true) { $64_bit_uninstall_string } Else { [string]'[not installed]' } } # New-Object $obj_maintenance.PSObject.TypeNames.Insert(0,"Maintenance") $obj_maintenance_selection = $obj_maintenance | Select-Object 'Open the Firefox primary profile location','Open the Firefox secondary profile location','Open the updates.xml file location','Uninstall the 32-bit Firefox','Uninstall the 64-bit Firefox' # Display the Maintenance table in console $empty_line | Out-String $header_maintenance = "Maintenance" $coline_maintenance = "-----------" Write-Output $header_maintenance $coline_maintenance | Out-String Write-Output $obj_maintenance_selection $obj_downloading += New-Object -TypeName PSCustomObject -Property @{ '32-bit Firefox' = If ($32_bit_firefox_is_installed -eq $true) { $downloading_firefox_32_is_required } Else { [string]'-' } '64-bit Firefox' = If ($64_bit_firefox_is_installed -eq $true) { $downloading_firefox_64_is_required } Else { [string]'-' } } # New-Object $obj_downloading.PSObject.TypeNames.Insert(0,"Maintenance Is Required for These Firefox Versions") $obj_downloading_selection = $obj_downloading | Select-Object '32-bit Firefox','64-bit Firefox' # Display in console which installers for Firefox need to be downloaded $empty_line | Out-String $header_downloading = "Maintenance Is Required for These Firefox Versions" $coline_downloading = "--------------------------------------------------" Write-Output $header_downloading $coline_downloading | Out-String Write-Output $obj_downloading_selection $empty_line | Out-String } Else { $continue = $true } # Else # Step 11 # Determine if there is a real need to carry on with the rest of the script. If ($firefox_is_installed -eq $true) { If (($downloading_firefox_is_required -eq $false) -and ($downloading_firefox_32_is_required -eq $false) -and ($downloading_firefox_64_is_required -eq $false)) { Return "The installed Firefox seems to be OK." } Else { $continue = $true } # Else } Else { Write-Warning "No Firefox seems to be installed on the system." $empty_line | Out-String $no_firefox_text_1 = "This script didn't detect that any version of Firefox would have been installed." $no_firefox_text_2 = "Please consider installing Firefox by visiting" $no_firefox_text_3 = "https://www.mozilla.org/en-US/firefox/all/" $no_firefox_text_4 = "For URLs of the full installation files please, for example, see the page" $no_firefox_text_5 = "https://ftp.mozilla.org/pub/firefox/releases/latest/README.txt" $no_firefox_text_6 = "and for uninstalling Firefox, please visit" $no_firefox_text_7 = "https://support.mozilla.org/en-US/kb/uninstall-firefox-from-your-computer" Write-Output $no_firefox_text_1 Write-Output $no_firefox_text_2 Write-Output $no_firefox_text_3 Write-Output $no_firefox_text_4 Write-Output $no_firefox_text_5 Write-Output $no_firefox_text_6 Write-Output $no_firefox_text_7 # Offer the option to install a specific version of Firefox, if no Firefox is detected and the script is run in an elevated window # Source: "Adding a Simple Menu to a Windows PowerShell Script": https://technet.microsoft.com/en-us/library/ff730939.aspx # Credit: lamaar75: "Creating a Menu": http://powershell.com/cs/forums/t/9685.aspx # Credit: alejandro5042: "How to run exe with/without elevated privileges from PowerShell" If (([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]"Administrator") -eq $true) { $empty_line | Out-String Write-Verbose "Welcome to the Admin Corner." -verbose $title_1 = "Install Firefox - The Fundamentals (Step 1/3)" $message_1 = "Would you like to install one of the Firefox versions (32-bit or 64-bit in a certain language) with this script?" $yes = New-Object System.Management.Automation.Host.ChoiceDescription "&Yes", "Yes: tries to download and install one of the Firefox versions specified on the next two steps." $no = New-Object System.Management.Automation.Host.ChoiceDescription "&No", "No: exits from this script (similar to Ctrl + C)." $exit = New-Object System.Management.Automation.Host.ChoiceDescription "&Exit", "Exit: exits from this script (similar to Ctrl + C)." $abort = New-Object System.Management.Automation.Host.ChoiceDescription "&Abort", "Abort: exits from this script (similar to Ctrl + C)." $cancel = New-Object System.Management.Automation.Host.ChoiceDescription "&Cancel", "Cancel: exits from this script (similar to Ctrl + C)." $options_1 = [System.Management.Automation.Host.ChoiceDescription[]]($yes, $no, $exit, $abort, $cancel) $result_1 = $host.ui.PromptForChoice($title_1, $message_1, $options_1, 1) switch ($result_1) { 0 { "Yes. Proceeding to the next step."; $admin_corner = $true $continue = $true } 1 { "No. Exiting from Install Firefox script."; Exit } 2 { "Exit. Exiting from Install Firefox script."; Exit } 3 { "Abort. Exiting from Install Firefox script."; Exit } 4 { "Cancel. Exiting from Install Firefox script."; Exit } # 4 } # switch $empty_line | Out-String $title_2 = "Install Firefox - The Bit Version (Step 2/3)" $message_2 = "Which bit version (32-bit or 64-bit) of Firefox would you like to install?" $32_bit = New-Object System.Management.Automation.Host.ChoiceDescription "&32-bit", "32-bit: tries to download and install the 32-bit version of Firefox." $64_bit = New-Object System.Management.Automation.Host.ChoiceDescription "&64-bit", "64-bit: tries to download and install the 64-bit version of Firefox." $options_2 = [System.Management.Automation.Host.ChoiceDescription[]]($32_bit, $64_bit, $exit, $abort, $cancel) $result_2 = $host.ui.PromptForChoice($title_2, $message_2, $options_2, 4) switch ($result_2) { 0 { "32-bit selected."; $firefox_is_installed = $true $32_bit_firefox_is_installed = $true $original_firefox_version = "[Nonexistent]" $downloading_firefox_is_required = $true $downloading_firefox_32_is_required = $true $os = '&os=win' $bit_number = "32" $continue = $true } 1 { "64-bit selected."; $firefox_is_installed = $true $64_bit_firefox_is_installed = $true $original_firefox_version = "[Nonexistent]" $downloading_firefox_is_required = $true $downloading_firefox_64_is_required = $true $os = '&os=win64' $bit_number = "64" $continue = $true } 2 { "Exit. Exiting from Install Firefox script."; Exit } 3 { "Abort. Exiting from Install Firefox script."; Exit } 4 { "Cancel. Exiting from Install Firefox script."; Exit } # 4 } # switch $empty_line | Out-String $title_3 = "Install Firefox - The Language (Step 3/3)" $message_3 = "Which language version of Firefox would you like to install?" $0 = New-Object System.Management.Automation.Host.ChoiceDescription "&0 English (US)", "English (US): tries to download and install the English (US) version of Firefox." $1 = New-Object System.Management.Automation.Host.ChoiceDescription "&1 English (British)", "English (British): tries to download and install the English (British) version of Firefox." $2 = New-Object System.Management.Automation.Host.ChoiceDescription "&2 Arabic", "Arabic: tries to download and install the Arabic version of Firefox." $3 = New-Object System.Management.Automation.Host.ChoiceDescription "&3 Chinese (Simplified)", "Chinese (Simplified): tries to download and install the Chinese (Simplified) version of Firefox." $4 = New-Object System.Management.Automation.Host.ChoiceDescription "&4 Chinese (Traditional)", "Chinese (Traditional): tries to download and install the Chinese (Traditional) version of Firefox." $5 = New-Object System.Management.Automation.Host.ChoiceDescription "&5 Dutch", "Dutch: tries to download and install the Dutch version of Firefox." $6 = New-Object System.Management.Automation.Host.ChoiceDescription "&6 French", "French: tries to download and install the French version of Firefox." $7 = New-Object System.Management.Automation.Host.ChoiceDescription "&7 German", "German: tries to download and install the German version of Firefox." $8 = New-Object System.Management.Automation.Host.ChoiceDescription "&8 Portuguese (Portugal)", "Portuguese (Portugal): tries to download and install the Portuguese (Portugal) version of Firefox." $9 = New-Object System.Management.Automation.Host.ChoiceDescription "&9 Spanish (Spain)", "Spanish (Spain): tries to download and install the Spanish (Spain) version of Firefox." $b = New-Object System.Management.Automation.Host.ChoiceDescription "&b Bengali (India)", "Bengali (India): tries to download and install the Bengali (India) version of Firefox." $d = New-Object System.Management.Automation.Host.ChoiceDescription "&d Danish", "Danish: tries to download and install the Danish version of Firefox." $f = New-Object System.Management.Automation.Host.ChoiceDescription "&f Finnish", "Finnish: tries to download and install the Finnish version of Firefox." $g = New-Object System.Management.Automation.Host.ChoiceDescription "&g Greek", "Greek: tries to download and install the Greek version of Firefox." $h = New-Object System.Management.Automation.Host.ChoiceDescription "&h Hebrew", "Hebrew: tries to download and install the Hebrew version of Firefox." $i = New-Object System.Management.Automation.Host.ChoiceDescription "&i Italian", "Italian: tries to download and install the Italian version of Firefox." $j = New-Object System.Management.Automation.Host.ChoiceDescription "&j Indonesian", "Indonesian: tries to download and install the Indonesian version of Firefox." $k = New-Object System.Management.Automation.Host.ChoiceDescription "&k Korean", "Korean: tries to download and install the Korean version of Firefox." $l = New-Object System.Management.Automation.Host.ChoiceDescription "&l Latvian", "Latvian: tries to download and install the Latvian version of Firefox." $m = New-Object System.Management.Automation.Host.ChoiceDescription "&m Malay", "Malay: tries to download and install the Malay version of Firefox." $n = New-Object System.Management.Automation.Host.ChoiceDescription "&n Norwegian (Nynorsk)", "Norwegian (Nynorsk): tries to download and install the Norwegian (Nynorsk) version of Firefox." $o = New-Object System.Management.Automation.Host.ChoiceDescription "&o Norwegian (Bokmal)", "Norwegian (Bokmal): tries to download and install the Norwegian (Bokmal) version of Firefox." $p = New-Object System.Management.Automation.Host.ChoiceDescription "&p Punjabi (India)", "Punjabi (India): tries to download and install the Punjabi (India) version of Firefox." $q = New-Object System.Management.Automation.Host.ChoiceDescription "&q Hindi (India)", "Hindi (India): tries to download and install the Hindi (India) version of Firefox." $r = New-Object System.Management.Automation.Host.ChoiceDescription "&r Romanian", "Romanian: tries to download and install the Romanian version of Firefox." $s = New-Object System.Management.Automation.Host.ChoiceDescription "&s Swedish", "Swedish: tries to download and install the Swedish version of Firefox." $t = New-Object System.Management.Automation.Host.ChoiceDescription "&t Thai", "Thai: tries to download and install the Thai version of Firefox." $u = New-Object System.Management.Automation.Host.ChoiceDescription "&u Ukrainian", "Ukrainian: tries to download and install the Ukrainian version of Firefox." $v = New-Object System.Management.Automation.Host.ChoiceDescription "&v Vietnamese", "Vietnamese: tries to download and install the Vietnamese version of Firefox." $w = New-Object System.Management.Automation.Host.ChoiceDescription "&w Welsh", "Welsh: tries to download and install the Welsh version of Firefox." $x = New-Object System.Management.Automation.Host.ChoiceDescription "&x Xhosa", "Xhosa: tries to download and install the Xhosa version of Firefox." $y = New-Object System.Management.Automation.Host.ChoiceDescription "&y Gaelic (Scotland)", "Gaelic (Scotland): tries to download and install the Gaelic (Scotland) version of Firefox." $z = New-Object System.Management.Automation.Host.ChoiceDescription "&z Uzbek", "Uzbek: tries to download and install the Uzbek version of Firefox." $options_3 = [System.Management.Automation.Host.ChoiceDescription[]]($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $b, $d, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, $q, $r, $s, $t, $u, $v, $w, $x, $y, $z, $exit, $abort, $cancel) $result_3 = $host.ui.PromptForChoice($title_3, $message_3, $options_3, 35) switch ($result_3) { 0 { "English (US) selected."; $lang = '&lang=en-US' $continue = $true } 1 { "English (British) selected."; $lang = '&lang=en-GB' $continue = $true } 2 { "Arabic selected."; $lang = '&lang=ar' $continue = $true } 3 { "Chinese (Simplified) selected."; $lang = '&lang=zh-CN' $continue = $true } 4 { "Chinese (Traditional) selected."; $lang = '&lang=zh-TW' $continue = $true } 5 { "Dutch selected."; $lang = '&lang=nl' $continue = $true } 6 { "French selected."; $lang = '&lang=fr' $continue = $true } 7 { "German selected."; $lang = '&lang=de' $continue = $true } 8 { "Portuguese (Portugal) selected."; $lang = '&lang=pt-PT' $continue = $true } 9 { "Spanish (Spain) selected."; $lang = '&lang=es-ES' $continue = $true } 10 { "Bengali (India) selected."; $lang = '&lang=bn-IN' $continue = $true } 11 { "Danish selected."; $lang = '&lang=da' $continue = $true } 12 { "Finnish selected."; $lang = 'lang=fi' $continue = $true } 13 { "Greek selected."; $lang = '&lang=el' $continue = $true } 14 { "Hebrew selected."; $lang = '&lang=he' $continue = $true } 15 { "Italian selected."; $lang = '&lang=it' $continue = $true } 16 { "Indonesian selected."; $lang = '&lang=id' $continue = $true } 17 { "Korean selected."; $lang = '&lang=ko' $continue = $true } 18 { "Latvian selected."; $lang = '&lang=lv' $continue = $true } 19 { "Malay selected."; $lang = '&lang=ms' $continue = $true } 20 { "Norwegian (Nynorsk) selected."; $lang = '&lang=nn-NO' $continue = $true } 21 { "Norwegian (Bokmal) selected."; $lang = '&lang=nb-NO' $continue = $true } 22 { "Punjabi (India) selected."; $lang = '&lang=pa-IN' $continue = $true } 23 { "Hindi (India) selected."; $lang = '&lang=hi-IN' $continue = $true } 24 { "Romanian selected."; $lang = '&lang=ro' $continue = $true } 25 { "Swedish selected."; $lang = '&lang=sv-SE' $continue = $true } 26 { "Thai selected."; $lang = '&lang=th' $continue = $true } 27 { "Ukrainian selected."; $lang = '&lang=uk' $continue = $true } 28 { "Vietnamese selected."; $lang = '&lang=vi' $continue = $true } 29 { "Welsh selected."; $lang = '&lang=cy' $continue = $true } 30 { "Xhosa selected."; $lang = '&lang=xh' $continue = $true } 31 { "Gaelic (Scotland) selected."; $lang = '&lang=gd' $continue = $true } 32 { "Uzbek selected."; $lang = '&lang=uz' $continue = $true } 33 { "Exit. Exiting from Install Firefox script."; Exit } 34 { "Abort. Exiting from Install Firefox script."; Exit } 35 { "Cancel. Exiting from Install Firefox script."; Exit } # 35 } # switch # Determine the Download URL based on the selections made by the user. # Source: https://ftp.mozilla.org/pub/firefox/releases/latest/README.txt # https://download.mozilla.org/?product=firefox-latest&os=win&lang=en-US $download_url = [string]'https://download.mozilla.org/?product=firefox-latest' + $os + $lang } Else { Exit } # Else (Admin Corner) } # Else (No Firefox ) # Step 12 # Check if the PowerShell session is elevated (has been run as an administrator) If (([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]"Administrator") -eq $false) { Write-Warning "It seems that this script is run in a 'normal' PowerShell window." $empty_line | Out-String Write-Verbose "Please consider running this script in an elevated (administrator-level) PowerShell window." -verbose $empty_line | Out-String $admin_text = "For performing system altering procedures, such as installing Firefox the elevated rights are mandatory. An elevated PowerShell session can, for example, be initiated by starting PowerShell with the 'run as an administrator' option." Write-Output $admin_text $empty_line | Out-String # Write-Verbose "Even though it could also be possible to write a self elevating PowerShell script (https://blogs.msdn.microsoft.com/virtual_pc_guy/2010/09/23/a-self-elevating-powershell-script/) or run commands elevated in PowerShell (http://powershell.com/cs/blogs/tips/archive/2014/03/19/running-commands-elevated-in-powershell.aspx) with the UAC prompts, the new UAC pop-up window may come as a surprise to the end-user, who isn't neccesarily aware that this script needs the elevated rights to complete the intended actions." Return "Exiting without updating (at Step 12)." } Else { $continue = $true } # Else # Step 13 # Initiate the update process $empty_line | Out-String $timestamp = Get-Date -Format HH:mm:ss $update_text = "$timestamp - Initiating the Firefox Update Protocol..." Write-Output $update_text # Determine the current directory # Credit: JaredPar and Matthew Pirocchi "What's the best way to determine the location of the current PowerShell script?" $script_path = Split-Path -parent $MyInvocation.MyCommand.Definition # "Manual" progress bar variables $activity = "Updating Firefox" $status = "Status" $id = 1 # For using more than one progress bar $total_steps = 19 # Total number of the steps or tasks, which will increment the progress bar $task_number = 0.2 # An increasing numerical value, which is set at the beginning of each of the steps that increments the progress bar (and the value should be less or equal to total_steps). In essence, this is the "progress" of the progress bar. $task = "Setting Initial Variables" # A description of the current operation, which is set at the beginning of each of the steps that increments the progress bar. # Start the progress bar Write-Progress -Id $id -Activity $activity -Status $status -CurrentOperation $task -PercentComplete (($task_number / $total_steps) * 100) # Specify [Esc] and [q] as the Cancel-key # Credit: Jeff: "Powershell show elapsed time" If ($Host.UI.RawUI.KeyAvailable -and ("q" -eq $Host.UI.RawUI.ReadKey("IncludeKeyUp,NoEcho").Character)) { Write-Host " ...Stopping the Firefox Update Protocol..."; Break; } ElseIf ($Host.UI.RawUI.KeyAvailable -and (([char]27) -eq $Host.UI.RawUI.ReadKey("IncludeKeyUp,NoEcho").Character)) { Write-Host " ...Stopping the Firefox Update Protocol..."; Break; } Else { $continue = $true } # Else # Step 14 # Write the Firefox installation configuration ini file # Description: Keep the default save location and the default shortcuts, but disable the Mozilla Maintenance service. # Source: https://wiki.mozilla.org/Installer:Command_Line_Arguments <# Silent install (always installs into the default location. Use the "Configuration ini file" option below to set the install location and other install options): -ms Silent uninstall: /S Configuration ini file (When specifying a configuration ini file the installer will always run silently): [/INI=] The silent install applies only to the full installer and not the stub installer. If you want to perform a silent install you cannot do so with the stub installer and you must use the full installer. Full installers for Firefox can be found at http://www.mozilla.org/firefox/all/ (or for Firefox ESR at http://www.mozilla.org/firefox/organizations/all/ ). #> $task_number = 1 $task = "Writing the Firefox installation configuration ini file..." Write-Progress -Id $id -Activity $activity -Status $status -CurrentOperation $task -PercentComplete (($task_number / $total_steps) * 100) $ini_file = "firefox_configuration.ini" $ini = New-Item -ItemType File -Path "$path\$ini_file" -Force $ini Add-Content $ini -Value ("[Install] ; ; Remove the semicolon (;) to un-comment a line. ; ; The name of the directory where the application will be installed in the ; system's program files directory. The security context the installer is ; running in must have write access to the installation directory. Also, the ; directory must not exist or if it exists it must be a directory and not a ; file. If any of these conditions are not met the installer will abort the ; installation with an error level of 2. If this value is specified ; then InstallDirectoryPath will be ignored. ; InstallDirectoryName=Mozilla Firefox ; The full path to the directory to install the application. The security ; context the installer is running in must have write access to the ; installation directory. Also, the directory must not exist or if it exists ; it must be a directory and not a file. If any of these conditions are not met ; the installer will abort the installation with an error level of 2. ; InstallDirectoryPath=c:\firefox\ ; By default all of the following shortcuts are created. To prevent the ; creation of a shortcut specify false for the shortcut you don't want created. ; Create a shortcut for the application in the current user's QuickLaunch ; directory. ; QuickLaunchShortcut=false ; Create a shortcut for the application on the desktop. This will create the ; shortcut in the All Users Desktop directory and if that fails this will ; attempt to create the shortcuts in the current user's Start Menu directory. ; DesktopShortcut=false ; Create shortcuts for the application in the Start Menu. This will create the ; shortcuts in the All Users Start Menu directory and if that fails this will ; attempt to create the shortcuts in the current user's Start Menu directory. ; StartMenuShortcuts=false ; The directory name to use for the StartMenu folder (not available with ; Firefox 4.0 and above - see the note below). ; Note: if StartMenuShortcuts=false is specified then this will be ignored. ; StartMenuDirectoryName=Mozilla Firefox ; The MozillaMaintenance service is used for silent updates and may be used ; for other maintenance related tasks. It is an optional component. This ; option can be used in Firefox 16 or later to skip installing the service. MaintenanceService=false") # Step 15 # Determine the required language version and the correct download URL # Source: https://ftp.mozilla.org/pub/firefox/releases/latest/README.txt # Source: https://wiki.mozilla.org/Software_Update:Checking_For_Updates # Source: http://kb.mozillazine.org/App.update.url <# # Download URL (clickable) https://www.mozilla.org/en-US/firefox/all/ # Check if the installed version of Firefox is the latest: https://www.mozilla.org/en-US/firefox/new/ # 32-bit English (US) Firefox for Windows: https://download.mozilla.org/?product=firefox-latest&os=win&lang=en-US # 64-bit English (US) Firefox for Windows: https://download.mozilla.org/?product=firefox-latest&os=win64&lang=en-US #> <# For other languages, please replace 'lang=en-US' with: Acholi lang=ach Afrikaans lang=af Albanian lang=sq Arabic lang=ar Aragonese lang=an Armenian lang=hy-AM Assamese lang=as Asturian lang=ast Azerbaijani lang=az Basque lang=eu Belarusian lang=be Bengali (Bangladesh) lang=bn-BD Bengali (India) lang=bn-IN Bosnian lang=bs Breton lang=br Bulgarian lang=bg Catalan lang=ca Chinese (Simplified) lang=zh-CN Chinese (Traditional) lang=zh-TW Croatian lang=hr Czech lang=cs Danish lang=da Dutch lang=nl English (British) lang=en-GB English (South African) lang=en-ZA Esperanto lang=eo Estonian lang=et Finnish lang=fi French lang=fr Frisian lang=fy-NL Fulah lang=ff Gaelic (Scotland) lang=gd Galician lang=gl German lang=de Greek lang=el Gujarati (India) lang=gu-IN Hebrew lang=he Hindi (India) lang=hi-IN Hungarian lang=hu Icelandic lang=is Indonesian lang=id Irish lang=ga-IE Italian lang=it Kannada lang=kn Kazakh lang=kk Khmer lang=km Korean lang=ko Latvian lang=lv Ligurian lang=lij Lithuanian lang=lt Lower Sorbian lang=dsb Macedonian lang=mk Maithili lang=mai Malay lang=ms Malayalam lang=ml Marathi lang=mr Norwegian (BokmÃ¥l) lang=nb-NO Norwegian (Nynorsk) lang=nn-NO Oriya lang=or Persian lang=fa Polish lang=pl Portuguese (Brazilian) lang=pt-BR Portuguese (Portugal) lang=pt-PT Punjabi (India) lang=pa-IN Romanian lang=ro Romansh lang=rm Russian lang=ru Serbian lang=sr Sinhala lang=si Slovak lang=sk Slovenian lang=sl Songhai lang=son Spanish (Argentina) lang=es-AR Spanish (Chile) lang=es-CL Spanish (Mexico) lang=es-MX Spanish (Spain) lang=es-ES Swedish lang=sv-SE Tamil lang=ta Telugu lang=te Thai lang=th Turkish lang=tr Ukrainian lang=uk Upper Sorbian lang=hsb Uzbek lang=uz Vietnamese lang=vi Welsh lang=cy Xhosa lang=xh https://download.mozilla.org/?product=firefox-50.0.2-SSL&os=win&lang=en-US https://download.mozilla.org/?product=firefox-50.0.2-complete&os=win&lang=en-US&force=1 https://download-installer.cdn.mozilla.net/pub/firefox/releases/50.0.2/win32/en-US/Firefox%20Setup%2050.0.2.exe https://download.mozilla.org/?product=firefox-50.0.2-SSL&os=win64&lang=en-US https://download.mozilla.org/?product=firefox-50.0.2-complete&os=win64&lang=en-US&force=1 https://download-installer.cdn.mozilla.net/pub/firefox/releases/50.0.2/win64/en-US/Firefox%20Setup%2050.0.2.exe about:config and search for app.update.url # Old Firefox: https://aus2.mozilla.org/update/3/Firefox/3.0a8pre/2007083015/Darwin_x86-gcc3/en-US/default/Darwin%208.10.1/testpartner/1.0/update.xml?force=1 # Firefox (trunk builds since 2010): https://aus3.mozilla.org/update/3/%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/update.xml # Firefox Current: https://aus5.mozilla.org/update/6/%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%SYSTEM_CAPABILITIES%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/update.xml '3' is the schema version PRODUCT: App name (e.g., 'Firefox') VERSION: App version (e.g., '3.0a8pre') BUILD_ID: Build ID (e.g., '2007083015') BUILD_TARGET: Build target (e.g., 'Darwin_x86-gcc3') LOCALE: App locale (e.g., 'en-US') CHANNEL: AUS channel (e.g., 'default') OS_VERSION: Operating System version (e.g., 'Darwin%208.10.1') DISTRIBUTION: Name of customized distribution, if any (e.g., 'testpartner') DISTRIBUTION_VERSION: Version of the customized distribution (e.g., '1.0) #> $task_number = 2 $task = "Determining the required language version and the correct download URL..." Write-Progress -Id $id -Activity $activity -Status $status -CurrentOperation $task -PercentComplete (($task_number / $total_steps) * 100) If (($multiple_firefoxes -ne $true) -and ($admin_corner -ne $true)) { If ($downloading_firefox_32_is_required -eq $true) { $os = '&os=win' $bit_number = "32" } ElseIf ($downloading_firefox_64_is_required -eq $true) { $os = '&os=win64' $bit_number = "64" } Else { $continue = $true } # Else # $system_language_and_region = (Get-Culture).Name # $system_language_abbreviation = (Get-Culture).TwoLetterISOLanguageName # $system_language = (Get-Culture).EnglishName If (($firefox_enumeration | select -ExpandProperty Locale) -ne $null) { $lang = [string]'&lang=' + ($firefox_enumeration | select -ExpandProperty Locale) } ElseIf (($firefox_enumeration | select -ExpandProperty Locale) -eq $null) { If ((($language | Select-Object -ErrorAction SilentlyContinue -ExpandProperty "$($(Get-Culture).TwoLetterISOLanguageName)").English) -match ((Get-Culture).EnglishName.split(' (')[0]) ) { $lang = [string]'&lang=' + $($(Get-Culture).TwoLetterISOLanguageName) } ElseIf ((($language | Select-Object -ErrorAction SilentlyContinue -ExpandProperty "$($(Get-Culture).Name)").English) -match ((Get-Culture).EnglishName) ) { $lang = [string]'&lang=' + $($(Get-Culture).Name) } ElseIf ((($language | Select-Object -ErrorAction SilentlyContinue -ExpandProperty "$($(Get-Culture).Name)").English) -match ((Get-Culture).EnglishName.split(' (')[0]) ) { $lang = [string]'&lang=' + $($(Get-Culture).Name) } ElseIf ((($language | Select-Object -ErrorAction SilentlyContinue -ExpandProperty "$($(Get-Culture).TwoLetterISOLanguageName)").English) -match ((Get-Culture).EnglishName) ) { $lang = [string]'&lang=' + $($(Get-Culture).TwoLetterISOLanguageName) } Else { $lang = [string]'&lang=' + (([Threading.Thread]::CurrentThread.CurrentUICulture).Name.Split("-")[0]) } # Else } Else { $continue = $true } # Else $download_url = [string]'https://download.mozilla.org/?product=firefox-latest' + $os + $lang } ElseIf (($multiple_firefoxes -ne $true) -and ($admin_corner -eq $true)) { $continue = $true } Else { Return "Multiple Firefox installations detected. Please update the relevant Firefox versions manually by visiting for example https://www.mozilla.org/en-US/firefox/all/ or run this script again after reducing the total number of Firefox installations to one. Exiting without updating (at Step 15)." } # Else (If $multiple_firefoxes) # Step 16 # Download the latest installation file for Firefox for Windows If (($firefox_is_installed -eq $true) -and ($downloading_firefox_is_required -eq $true)) { $task_number = 4 $task = "Downloading a full offline $bit_number-bit Firefox installer from $download_url" Write-Progress -Id $id -Activity $activity -Status $status -CurrentOperation $task -PercentComplete (($task_number / $total_steps) * 100) $download_file = "Firefox_Setup.exe" $firefox_save_location = "$path\$download_file" $firefox_is_downloaded = $false # Purge existing old Firefox installation files If ((Test-Path $firefox_save_location) -eq $true) { Write-Verbose "Deleting $firefox_save_location" Remove-Item -Path "$firefox_save_location" } Else { $continue = $true } # Else try { $download_firefox = New-Object System.Net.WebClient $download_firefox.DownloadFile($download_url, $firefox_save_location) } catch [System.Net.WebException] { Write-Warning "Failed to access $download_url" $empty_line | Out-String Return "Exiting without installing a new Firefox version (at Step 16)." } Start-Sleep -s 2 If ((Test-Path $firefox_save_location) -eq $true) { $firefox_is_downloaded = $true } Else { $firefox_is_downloaded = $false } # Else } Else { $continue = $true } # Else # Step 17 # Exit all browsers $task_number = 8 $task = "Stopping Firefox -related processes..." Write-Progress -Id $id -Activity $activity -Status $status -CurrentOperation $task -PercentComplete (($task_number / $total_steps) * 100) Stop-Process -ProcessName '*messenger*' -ErrorAction SilentlyContinue -Force Stop-Process -ProcessName 'FlashPlayer*' -ErrorAction SilentlyContinue -Force Stop-Process -ProcessName 'plugin-container*' -ErrorAction SilentlyContinue -Force Stop-Process -ProcessName 'chrome*' -ErrorAction SilentlyContinue -Force Stop-Process -ProcessName 'opera*' -ErrorAction SilentlyContinue -Force Stop-Process -ProcessName 'firefox' -ErrorAction SilentlyContinue -Force Stop-Process -ProcessName 'iexplore' -ErrorAction SilentlyContinue -Force Start-Sleep -s 4 # Step 18 # Install Firefox silently on top of the existing Firefox installation # For the Firefox installation configuration ini file, please see the Step 14. # Source: https://wiki.mozilla.org/Installer:Command_Line_Arguments <# Silent install (always installs into the default location. Use the "Configuration ini file" option below to set the install location and other install options): -ms Silent uninstall: /S Configuration ini file (When specifying a configuration ini file the installer will always run silently): [/INI=] The silent install applies only to the full installer and not the stub installer. If you want to perform a silent install you cannot do so with the stub installer and you must use the full installer. Full installers for Firefox can be found at http://www.mozilla.org/firefox/all/ (or for Firefox ESR at http://www.mozilla.org/firefox/organizations/all/ ). #> $task_number = 11 $task = "Installing Firefox..." Write-Progress -Id $id -Activity $activity -Status $status -CurrentOperation $task -PercentComplete (($task_number / $total_steps) * 100) If ($firefox_is_downloaded -eq $true) { $task_number = 10 $task = "Installing Firefox..." Write-Progress -Id $id -Activity $activity -Status $status -CurrentOperation $task -PercentComplete (($task_number / $total_steps) * 100) cd $path .\Firefox_Setup.exe /INI="$path\$ini_file" | Out-Null cd $script_path Start-Sleep -s 5 } Else { $continue = $true } # Else # Step 19 # Try to find out which Firefox versions, if any, are installed on the system after the update $task_number = 15 $task = "Enumerating the Firefox versions found on the system after the update..." Write-Progress -Id $id -Activity $activity -Status $status -CurrentOperation $task -PercentComplete (($task_number / $total_steps) * 100) # Determine whether Firefox is installed or not $firefox_is_installed = $false If ((Check-InstalledSoftware "*Firefox*") -ne $null) { $firefox_is_installed = $true } Else { $continue = $true } # Else # Enumerate the installed Firefoxes after the update $32_bit_firefox_is_installed = $false $64_bit_firefox_is_installed = $false $registry_paths_after_update = Get-ItemProperty $registry_paths -ErrorAction SilentlyContinue | Where-Object { ($_.DisplayName -like "*Firefox*" ) -and ($_.Publisher -like "Mozilla*" )} If ($registry_paths_after_update -ne $null) { ForEach ($new_firefox in $registry_paths_after_update) { # Custom Values If (($new_firefox.DisplayName.Split(" ")[-1] -match "\(") -eq $false) { $locale_new = ($new_firefox.DisplayName.Split(" ")[-1]).Replace(")","") } Else { $continue = $true } # Else If (($new_firefox.DisplayName.Split(" ")[-1] -match "\(x") -eq $true) { If ($new_firefox.DisplayName.Split(" ")[-1] -like "(x86") { $32_bit_firefox_is_installed = $true $type_new = "32-bit" } ElseIf ($new_firefox.DisplayName.Split(" ")[-1] -like "(x64") { $64_bit_firefox_is_installed = $true $type_new = "64-bit" } Else { $continue = $true } # Else } ElseIf (($new_firefox.DisplayName.Split(" ")[-2] -match "\(x") -eq $true) { If ($new_firefox.DisplayName.Split(" ")[-2] -like "(x86") { $32_bit_firefox_is_installed = $true $type_new = "32-bit" } ElseIf ($new_firefox.DisplayName.Split(" ")[-2] -like "(x64") { $64_bit_firefox_is_installed = $true $type_new = "64-bit" } Else { $continue = $true } # Else } Else { $continue = $true } # Else $product_version_new = ((Get-ItemProperty -Path "$($new_firefox.InstallLocation)\Firefox.exe" -ErrorAction SilentlyContinue -Name VersionInfo).VersionInfo).ProductVersion $regex_stability = $product_version_new -match "(\d+)\.(\d+)\.(\d+)" $regex_major = $product_version_new -match "(\d+)\.(\d+)" If (($product_version_new -ne $null) -and ($regex_stability -eq $true)) { $product_version_new -match "(?\d+)\.(?\d+)\.(?\d+)" } Else { $continue = $true } If (($product_version_new -ne $null) -and ($regex_stability -eq $false) -and ($regex_major -eq $true)) { $product_version_new -match "(?\d+)\.(?\d+)" } Else { $continue = $true } $after_update_firefoxes += $obj_updated_firefox = New-Object -TypeName PSCustomObject -Property @{ 'Name' = $new_firefox.DisplayName.Replace("(TM)","") 'Publisher' = $new_firefox.Publisher 'Product' = $new_firefox.DisplayName.Split(" ")[1] 'Type' = $type_new 'Locale' = $locale_new 'Major Version' = If ($Matches.B1 -ne $null) { $Matches.B1 } Else { $continue = $true } 'Minor Version' = If ($Matches.B2 -ne $null) { $Matches.B2 } Else { $continue = $true } 'Build Number' = If ($Matches.B3 -ne $null) { $Matches.B3 } Else { "-" } 'Computer' = $computer 'Install Location' = $new_firefox.InstallLocation 'Standard Uninstall String' = $new_firefox.UninstallString.Trim('"') 'Release Notes' = $new_firefox.URLUpdateInfo 'Identifying Number' = $new_firefox.PSChildName 'Version' = $new_firefox.DisplayVersion } # New-Object } # foreach ($new_firefox) # Display the Firefox Version Enumeration in console If ($after_update_firefoxes -ne $null) { $after_update_firefoxes.PSObject.TypeNames.Insert(0,"Firefox Versions After the Update") $after_update_firefoxes_selection = $after_update_firefoxes | Select-Object 'Name','Publisher','Product','Type','Locale','Major Version','Minor Version','Build Number','Computer','Install Location','Standard Uninstall String','Release Notes','Version' $empty_line | Out-String $header_new = "Firefox Versions Found on the System After the Update" $coline_new = "-----------------------------------------------------" Write-Output $header_new $coline_new | Out-String Write-Output $after_update_firefoxes_selection } Else { $continue = $true } # Else } Else { $continue = $true } # Else (Step 19) # Step 20 # Determine the success rate of the update process. $task_number = 16 $task = "Determining the success rate of the update process..." Write-Progress -Id $id -Activity $activity -Status $status -CurrentOperation $task -PercentComplete (($task_number / $total_steps) * 100) $multiple_firefoxes_after_update = $false If ((($after_update_firefoxes | Measure-Object Name).Count) -eq 0) { $success = $false $empty_line | Out-String Write-Warning "No Firefox seems to be installed on the system." $empty_line | Out-String Return "The most recent non-beta Firefox version is $most_recent_firefox_version. This script tried to update Firefox, but something went wrong with the installation. Instead of updating Firefox this script uninstalled all versions of Firefox. Exiting at Step 20." } ElseIf ((($after_update_firefoxes | Measure-Object Name).Count) -eq 1) { # One instance of Firefox seems to be installed. $continue = $true } ElseIf ((($after_update_firefoxes | Measure-Object Name).Count) -ge 2) { $success = $false $empty_line | Out-String Write-Warning "More than one instance of Firefox seems to be installed on the system." $multiple_firefoxes_after_update = $true $empty_line | Out-String Return "The most recent non-beta Firefox version is $most_recent_firefox_version. This script tried to update Firefox, but something went wrong with the installation. Instead of updating Firefox this script installed yet another version of Firefox. Currently the versions $($after_update_firefoxes.Version) are installed. Exiting at Step 20." } Else { $continue = $true } # Else $most_recent_firefox_after_update = Check-InstalledSoftware "Mozilla Firefox $($most_recent_firefox_version)*" If (($firefox_is_installed -eq $true) -and ($downloading_firefox_is_required -eq $true) -and ($after_update_firefoxes -ne $null) -and ($multiple_firefoxes_after_update -eq $false)) { If ($most_recent_firefox_after_update -eq $null) { $success = $false $empty_line | Out-String Write-Warning "Failed to update Mozilla Firefox" $empty_line | Out-String Return "$($after_update_firefoxes.Name) seems to be outdated. The most recent non-beta Firefox version is $most_recent_firefox_version. The installed Firefox version $($after_update_firefoxes.Version) needs to be updated. This script tried to update Firefox, but failed to do so." } ElseIf ($most_recent_firefox_after_update) { $success = $true $locale = If (($most_recent_firefox_after_update.DisplayName.Split(" ")[-1] -match "\(") -eq $false) { If ($powershell_v2_or_earlier -eq $true) { $language.Get_Item(($most_recent_firefox_after_update.DisplayName.Split(" ")[-1]).Replace(")","")) } Else { $language | Select-Object -ExpandProperty (($most_recent_firefox_after_update.DisplayName.Split(" ")[-1]).Replace(")","")) } # Else } Else { $continue = $true } # Else ($locale) If ($powershell_v2_or_earlier -eq $true) { try { $release_date = $all_dates.Get_Item($most_recent_firefox_after_update.DisplayVersion) } catch { $message = $error[0].Exception Write-Verbose $message } } Else { try { $release_date = $all_dates | Select-Object -ExpandProperty $most_recent_firefox_after_update.DisplayVersion } catch { $message = $error[0].Exception Write-Verbose $message } } # Else $obj_success_firefox += New-Object -TypeName PSCustomObject -Property @{ 'Name' = $most_recent_firefox_after_update.DisplayName.replace("(TM)","") 'Publisher' = $most_recent_firefox_after_update.Publisher 'Product' = $most_recent_firefox_after_update.DisplayName.Split(" ")[1] 'Type' = $after_update_firefoxes.Type 'Locale' = $locale 'Computer' = $computer 'Install_Location' = $most_recent_firefox_after_update.InstallLocation 'Release Notes' = $most_recent_firefox_after_update.URLUpdateInfo 'Standard Uninstall String' = $most_recent_firefox_after_update.UninstallString.Trim('"') 'Identifying Number' = $most_recent_firefox_after_update.PSChildName 'Release_Date' = $release_date 'Version' = $most_recent_firefox_after_update.DisplayVersion } # New-Object $obj_success_firefox.PSObject.TypeNames.Insert(0,"Successfully Updated Firefox Version") $empty_line | Out-String Write-Output "Currently (until the next Firefox version is released) the $($($obj_success_firefox.Locale).English) $($obj_success_firefox.Type) $($obj_success_firefox.Name) released on $((Get-Date ($obj_success_firefox.Release_Date)).ToShortDateString()) doesn't need any further maintenance or care." $empty_line | Out-String Write-Output "The installed Firefox seems to be OK." } Else { $continue = $true } # Else } Else { $continue = $true } # Else # Step 21 # Check if the installed version of Firefox is the latest by opening a web page in the default browser # Congrats! You're using the latest version of Firefox. $task_number = 17 $task = "Verifying that the Firefox has been installed by opening a web page in the default browser..." Write-Progress -Id $id -Activity $activity -Status $status -CurrentOperation $task -PercentComplete (($task_number / $total_steps) * 100) If ($obj_success_firefox -ne $null) { Start-Process -FilePath "$($obj_success_firefox.Install_Location)\firefox.exe" -ArgumentList "https://www.mozilla.org/en-US/firefox/new/" } Else { $continue = $true } # Else # Step 22 # Close the progress bar $task_number = 19 $task = "Finished updating Firefox." Write-Progress -Id $id -Activity $activity -Status $status -CurrentOperation $task -PercentComplete (($task_number / $total_steps) * 100) -Completed # Find out how long the script took to complete $end_time = Get-Date $runtime = ($end_time) - ($start_time) If ($runtime.Days -ge 2) { $runtime_result = [string]$runtime.Days + ' days ' + $runtime.Hours + ' h ' + $runtime.Minutes + ' min' } ElseIf ($runtime.Days -gt 0) { $runtime_result = [string]$runtime.Days + ' day ' + $runtime.Hours + ' h ' + $runtime.Minutes + ' min' } ElseIf ($runtime.Hours -gt 0) { $runtime_result = [string]$runtime.Hours + ' h ' + $runtime.Minutes + ' min' } ElseIf ($runtime.Minutes -gt 0) { $runtime_result = [string]$runtime.Minutes + ' min ' + $runtime.Seconds + ' sec' } ElseIf ($runtime.Seconds -gt 0) { $runtime_result = [string]$runtime.Seconds + ' sec' } ElseIf ($runtime.Milliseconds -gt 1) { $runtime_result = [string]$runtime.Milliseconds + ' milliseconds' } ElseIf ($runtime.Milliseconds -eq 1) { $runtime_result = [string]$runtime.Milliseconds + ' millisecond' } ElseIf (($runtime.Milliseconds -gt 0) -and ($runtime.Milliseconds -lt 1)) { $runtime_result = [string]$runtime.Milliseconds + ' milliseconds' } Else { $runtime_result = [string]'' } # Else (if) If ($runtime_result.Contains(" 0 h")) { $runtime_result = $runtime_result.Replace(" 0 h"," ") } If ($runtime_result.Contains(" 0 min")) { $runtime_result = $runtime_result.Replace(" 0 min"," ") } If ($runtime_result.Contains(" 0 sec")) { $runtime_result = $runtime_result.Replace(" 0 sec"," ") } # if ($runtime_result: first) # Display the runtime in console $empty_line | Out-String $timestamp_end = Get-Date -Format hh:mm:ss $end_text = "$timestamp_end - The Firefox Update Protocol completed." Write-Output $end_text $empty_line | Out-String $runtime_text = "The update took $runtime_result." Write-Output $runtime_text $empty_line | Out-String # [End of Line] <# _____ / ____| | (___ ___ _ _ _ __ ___ ___ \___ \ / _ \| | | | '__/ __/ _ \ ____) | (_) | |_| | | | (_| __/ |_____/ \___/ \__,_|_| \___\___| http://powershell.com/cs/PowerTips_Monthly_Volume_8.pdf#IDERA-1702_PS-PowerShellMonthlyTipsVol8-jan2014 # Tobias Weltner: "PowerTips Monthly vol 8 January 2014" http://powershell.com/cs/blogs/tips/archive/2011/05/04/test-internet-connection.aspx # ps1: "Test Internet connection" http://stackoverflow.com/questions/17601528/read-json-object-in-powershell-2-0#17602226 # Goyuix: "Read Json Object in Powershell 2.0" http://powershell.com/cs/forums/t/9685.aspx # lamaar75: "Creating a Menu" http://stackoverflow.com/questions/29266622/how-to-run-exe-with-without-elevated-privileges-from-powershell?rq=1 # alejandro5042: "How to run exe with/without elevated privileges from PowerShell" http://stackoverflow.com/questions/5466329/whats-the-best-way-to-determine-the-location-of-the-current-powershell-script?noredirect=1&lq=1 # JaredPar and Matthew Pirocchi "What's the best way to determine the location of the current PowerShell script?" http://stackoverflow.com/questions/10941756/powershell-show-elapsed-time # Jeff: "Powershell show elapsed time" _ _ _ | | | | | | | |__| | ___| |_ __ | __ |/ _ \ | '_ \ | | | | __/ | |_) | |_| |_|\___|_| .__/ | | |_| #> <# .SYNOPSIS Retrieves the latest Mozilla Firefox version numbers from the Internets, and looks for the installed Firefox versions on the system. If an outdated Firefox version is found, tries to update Firefox. .DESCRIPTION Update-MozillaFirefox downloads a list of the most recent Firefox version numbers against which it compares the Firefox version numbers found on the system and displays, whether a Firefox update is needed or not. Update-MozillaFirefox detects the installed Firefoxes by querying the Windows registry for installed programs. The keys from HKLM:\Software\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\ and HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\ are read on 64-bit computers, and on the 32-bit computers only the latter path is accessed. At Step 7 Update-MozillaFirefox downloads and writes several Firefox-related files, namely "firefox_current_versions.json", "firefox_release_history.json", "firefox_major_versions.json", "firefox_languages.json" and "firefox_regions.json", which Update-MozillaFirefox uses as data sources. When run in a 'normal' PowerShell window, and all the detected Firefox versions seem to be up-to-date, Update-MozillaFirefox will just check that everything is OK and leave without further ceremony at Step 11. If Update-MozillaFirefox is run without elevated rights (but with a working Internet connection) in a machine with an old Firefox version, it will be shown that a Firefox update is needed, but Update-MozillaFirefox will exit at Step 12 before downloading any files. To perform an update with Update-MozillaFirefox, PowerShell has to be run in an elevated window (run as an administrator). If Update-MozillaFirefox is run in an elevated PowerShell window and no Firefox is detected, the script offers the option to install Firefox in the "Admin Corner" (step 11), where, in contrary to the main autonomous nature of Update-MozillaFirefox, an end-user input is required for selecting the bit-version and the language. In the "Admin Corner", one instance of either 32-bit or 64-bit version in one of the available languages is installable with Update-MozillaFirefox – the language selection covers over 30 languages. In the update procedure itself Update-MozillaFirefox downloads a full Firefox installer from Mozilla, which is equal to the type that is already installed on the system (same bit version and language). After writing the Install Configuration File (firefox_configuration.ini to $path at Step 14, where, for instance, the automatic Mozilla Maintenance service is disabled and the default shortcuts are enabled) and stopping several Firefox-related processes, Update-MozillaFirefox installs the downloaded Firefox on top of the existing Firefox installation, which triggers the in-built Firefox update procedure. .OUTPUTS Displays Firefox related information in console. Tries to update an outdated Firefox to its latest version, if an old Firefox installation is found, and if Update-MozillaFirefox is run in an elevated Powershell window. In addition to that... At Step 7 the baseline Firefox version numbers are written to a file (firefox_current_versions.json) and also four additional auxillary JSON files are created, namely: Firefox JSON Files (at Step 7): firefox_current_versions.json %TEMP%\firefox_current_versions.json firefox_release_history.json %TEMP%\firefox_release_history.json firefox_major_versions.json %TEMP%\firefox_major_versions.json firefox_languages.json %TEMP%\firefox_languages.json firefox_regions.json %TEMP%\firefox_regions.json The %TEMP% location represents the current Windows temporary file folder. In PowerShell, for instance the the command $env:temp displays the temp-folder path. If the actual update procedure including the installation file downloading is initiated, a Firefox Install Configuration File (firefox_configuration.ini) is created with one active parameter (other parameters inside the file are commented out): Install Configuration File (at Step 14): firefox_configuration.ini %TEMP%\firefox_configuration.ini The %TEMP% location represents the current Windows temporary file folder. In PowerShell, for instance the the command $env:temp displays the temp-folder path. To see the actual values that are being written, please see the Step 14 above, where the following value is written: (altering the duplicated value below won't affect the script in any meaningful way) MaintenanceService=false The MozillaMaintenance service is used for silent updates and may be used for other maintenance related tasks. It is an optional component. This option can be used in Firefox 16 or later to skip installing the service. For a comprehensive list of available settings and a more detailed description of the value above, please see the "Installer:Command Line Arguments" at https://wiki.mozilla.org/Installer:Command_Line_Arguments To open these file locations in a Resource Manager Window, for instance a command Invoke-Item $env:temp may be used at the PowerShell prompt window [PS>]. .NOTES Requires either (a) PowerShell v3 or later or (b) .NET 3.5 or later for importing and converting JSON-files (at Step 8). Requires a working Internet connection for downloading a list of the most recent Firefox version numbers and for downloading a complete Firefox installer from Mozilla (but the latter procedure is not initiated, if the system is deemed up-to-date). For performing any actual updates with Update-MozillaFirefox, it's mandatory to run this script in an elevated PowerShell window (where PowerShell has been started with the 'run as an administrator' option). The elevated rights are needed for installing Firefox on top of the exising Firefox installation. Update-MozillaFirefox is designed to update only one instance of Firefox. If more than one instances of Firefox are detected, the script will notify the user in Step 5, and furthermore, if old Firefox(es) are detected, the script will exit before downloading the installation file at Step 15. Please note that the Firefox installation configuration file written at Step 14 disables the Mozilla Maintenance service so that the Mozilla Maintenance service will not be installed during the Firefox update. The values set with the Install Configuration File (firefox_configuration.ini) are altering the system files and seemingly are written somewhere deeper to the innards of Mozilla Firefox semi-permanently. Please also notice that when run in an elevated PowerShell window and an old Firefox version is detected, Update-MozillaFirefox will automatically try to download files from the Internet without prompting the end-user beforehand or without asking any confirmations (at Step 16 and onwards) and at Step 17 closes a bunch of processes without any further notice. Please note that the downloaded files are placed in a directory, which is specified with the $path variable (at line 42). The $env:temp variable points to the current temp folder. The default value of the $env:temp variable is C:\Users\\AppData\Local\Temp (i.e. each user account has their own separate temp folder at path %USERPROFILE%\AppData\Local\Temp). To see the current temp path, for instance a command [System.IO.Path]::GetTempPath() may be used at the PowerShell prompt window [PS>]. To change the temp folder for instance to C:\Temp, please, for example, follow the instructions at http://www.eightforums.com/tutorials/23500-temporary-files-folder-change-location-windows.html Homepage: https://github.com/auberginehill/update-mozilla-firefox Short URL: http://tinyurl.com/gr75tjx Version: 1.6 .EXAMPLE ./Update-MozillaFirefox Runs the script. Please notice to insert ./ or .\ before the script name. .EXAMPLE help ./Update-MozillaFirefox -Full Displays the help file. .EXAMPLE Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope LocalMachine This command is altering the Windows PowerShell rights to enable script execution in the default (LocalMachine) scope, and defines the conditions under which Windows PowerShell loads configuration files and runs scripts in general. In Windows Vista and later versions of Windows, for running commands that change the execution policy of the LocalMachine scope, Windows PowerShell has to be run with elevated rights (Run as Administrator). The default policy of the default (LocalMachine) scope is "Restricted", and a command "Set-ExecutionPolicy Restricted" will "undo" the changes made with the original example above (had the policy not been changed before...). Execution policies for the local computer (LocalMachine) and for the current user (CurrentUser) are stored in the registry (at for instance the HKLM:\Software\Policies\Microsoft\Windows\PowerShell\ExecutionPolicy key), and remain effective until they are changed again. The execution policy for a particular session (Process) is stored only in memory, and is discarded when the session is closed. Parameters: Restricted Does not load configuration files or run scripts, but permits individual commands. Restricted is the default execution policy. AllSigned Scripts can run. Requires that all scripts and configuration files be signed by a trusted publisher, including the scripts that have been written on the local computer. Risks running signed, but malicious, scripts. RemoteSigned Requires a digital signature from a trusted publisher on scripts and configuration files that are downloaded from the Internet (including e-mail and instant messaging programs). Does not require digital signatures on scripts that have been written on the local computer. Permits running unsigned scripts that are downloaded from the Internet, if the scripts are unblocked by using the Unblock-File cmdlet. Risks running unsigned scripts from sources other than the Internet and signed, but malicious, scripts. Unrestricted Loads all configuration files and runs all scripts. Warns the user before running scripts and configuration files that are downloaded from the Internet. Not only risks, but actually permits, eventually, running any unsigned scripts from any source. Risks running malicious scripts. Bypass Nothing is blocked and there are no warnings or prompts. Not only risks, but actually permits running any unsigned scripts from any source. Risks running malicious scripts. Undefined Removes the currently assigned execution policy from the current scope. If the execution policy in all scopes is set to Undefined, the effective execution policy is Restricted, which is the default execution policy. This parameter will not alter or remove the ("master") execution policy that is set with a Group Policy setting. __________ Notes: - Please note that the Group Policy setting "Turn on Script Execution" overrides the execution policies set in Windows PowerShell in all scopes. To find this ("master") setting, please, for example, open the Local Group Policy Editor (gpedit.msc) and navigate to Computer Configuration > Administrative Templates > Windows Components > Windows PowerShell. - The Local Group Policy Editor (gpedit.msc) is not available in any Home or Starter edition of Windows. - Group Policy setting "Turn on Script Execution": Not configured : No effect, the default value of this setting Disabled : Restricted Enabled - Allow only signed scripts : AllSigned Enabled - Allow local scripts and remote signed scripts : RemoteSigned Enabled - Allow all scripts : Unrestricted For more information, please type "Get-ExecutionPolicy -List", "help Set-ExecutionPolicy -Full", "help about_Execution_Policies" or visit https://technet.microsoft.com/en-us/library/hh849812.aspx or http://go.microsoft.com/fwlink/?LinkID=135170. .EXAMPLE New-Item -ItemType File -Path C:\Temp\Update-MozillaFirefox.ps1 Creates an empty ps1-file to the C:\Temp directory. The New-Item cmdlet has an inherent -NoClobber mode built into it, so that the procedure will halt, if overwriting (replacing the contents) of an existing file is about to happen. Overwriting a file with the New-Item cmdlet requires using the Force. If the path name and/or the filename includes space characters, please enclose the whole -Path parameter value in quotation marks (single or double): New-Item -ItemType File -Path "C:\Folder Name\Update-MozillaFirefox.ps1" For more information, please type "help New-Item -Full". .LINK http://powershell.com/cs/PowerTips_Monthly_Volume_8.pdf#IDERA-1702_PS-PowerShellMonthlyTipsVol8-jan2014 http://powershell.com/cs/blogs/tips/archive/2011/05/04/test-internet-connection.aspx http://stackoverflow.com/questions/17601528/read-json-object-in-powershell-2-0#17602226 http://powershell.com/cs/forums/t/9685.aspx http://stackoverflow.com/questions/29266622/how-to-run-exe-with-without-elevated-privileges-from-powershell?rq=1 http://stackoverflow.com/questions/5466329/whats-the-best-way-to-determine-the-location-of-the-current-powershell-script?noredirect=1&lq=1 http://stackoverflow.com/questions/10941756/powershell-show-elapsed-time http://stackoverflow.com/questions/1825585/determine-installed-powershell-version?rq=1 https://msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powershell.utility/convertfrom-json https://msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powershell.utility/convertfrom-stringdata https://blogs.technet.microsoft.com/heyscriptingguy/2014/04/23/powertip-convert-json-file-to-powershell-object/ http://stackoverflow.com/questions/32887583/powershell-v2-converts-dictionary-to-array-when-returned-from-a-function http://powershelldistrict.com/powershell-json/ https://technet.microsoft.com/en-us/library/ff730939.aspx https://technet.microsoft.com/en-us/library/ee692803.aspx https://www.credera.com/blog/technology-insights/perfect-progress-bars-for-powershell/ http://kb.mozillazine.org/Software_Update https://wiki.mozilla.org/Installer:Command_Line_Arguments https://wiki.mozilla.org/Software_Update:Checking_For_Updates https://ftp.mozilla.org/pub/firefox/releases/latest/README.txt http://kb.mozillazine.org/App.update.url #>