<# .SYNOPSIS Get-EdgeEnterpriseMSI .DESCRIPTION Imports all device configurations in a folder to a specified tenant .PARAMETER Channel Channel to download, Valid Options are: Dev, Beta, Stable, EdgeUpdate, Policy. .PARAMETER Platform Platform to download, Valid Options are: Windows or MacOS, if using channel "Policy" this should be set to "any" Defaults to Windows if not set. .PARAMETER Architecture Architecture to download, Valid Options are: x86, x64, arm64, if using channel "Policy" this should be set to "any" Defaults to x64 if not set. .PARAMETER Version If set the script will try and download a specific version. If not set it will download the latest. .PARAMETER Folder Specifies the Download folder .PARAMETER Force Overwrites the file without asking. .NOTES Version: 1.2 Author: Mattias Benninge Creation Date: 2020-07-01 Version history: 1.0 - Initial script development 1.1 - Fixes and improvements by @KarlGrindon - Script now handles multiple files for e.g. MacOS Edge files - Better error handling and formating - URI Validation 1.2 - Better compability on servers (force TLS and remove dependency to IE) https://docs.microsoft.com/en-us/mem/configmgr/apps/deploy-use/deploy-edge .EXAMPLE Download the latest version for the Beta channel and overwrite any existing file .\Get-EdgeEnterpriseMSI.ps1 -Channel Beta -Folder D:\SourceCode\PowerShell\Div -Force #> [CmdletBinding()] param( [Parameter(Mandatory = $True, HelpMessage = 'Channel to download, Valid Options are: Dev, Beta, Stable, EdgeUpdate, Policy')] [ValidateSet('Dev', 'Beta', 'Stable', 'EdgeUpdate', 'Policy')] [string]$Channel = "Stable", [Parameter(Mandatory = $True, HelpMessage = 'Folder where the file will be downloaded')] [ValidateNotNullOrEmpty()] [string]$Folder = "C:\temp", [Parameter(Mandatory = $false, HelpMessage = 'Platform to download, Valid Options are: Windows or MacOS')] [ValidateSet('Windows', 'MacOS', 'any')] [string]$Platform = "Windows", [Parameter(Mandatory = $false, HelpMessage = "Architecture to download, Valid Options are: x86, x64, arm64, any")] [ValidateSet('x86', 'x64', 'arm64', 'any')] [string]$Architecture = "x64", [parameter(Mandatory = $false, HelpMessage = "Specifies which version to download")] [ValidateNotNullOrEmpty()] [string]$ProductVersion, [parameter(Mandatory = $false, HelpMessage = "Overwrites the file without asking")] [Switch]$Force ) $ErrorActionPreference = "Stop" $edgeEnterpriseMSIUri = 'https://edgeupdates.microsoft.com/api/products?view=enterprise' # Validating parameters to reduce user errors if ($Channel -eq "Policy" -and ($Architecture -ne "Any" -or $Platform -ne "Any")) { Write-Warning ("Channel 'Policy' requested, but either 'Architecture' and/or 'Platform' is not set to 'Any'. Setting Architecture and Platform to 'Any'") $Architecture = "Any" $Platform = "Any" } elseif ($Channel -ne "Policy" -and ($Architecture -eq "Any" -or $Platform -eq "Any")) { throw "If Channel isn't set to policy, architecture and/or platform can't be set to 'Any'" } elseif ($Channel -eq "EdgeUpdate" -and ($Architecture -ne "x86" -or $Platform -eq "Windows")) { Write-Warning ("Channel 'EdgeUpdate' requested, but either 'Architecture' is not set to x86 and/or 'Platform' is not set to 'Windows'. Setting Architecture to 'x86' and Platform to 'Windows'") $Architecture = "x86" $Platform = "Windows" } Write-Host "Enabling connection over TLS for better compability on servers" -ForegroundColor Green [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls -bor [Net.SecurityProtocolType]::Tls11 -bor [Net.SecurityProtocolType]::Tls12 # Test if HTTP status code 200 is returned from URI try { Invoke-WebRequest $edgeEnterpriseMSIUri -UseBasicParsing | Where-Object StatusCode -match 200 | Out-Null } catch { throw "Unable to get HTTP status code 200 from $edgeEnterpriseMSIUri. Does the URL still exist?" } Write-Host "Getting available files from $edgeEnterpriseMSIUri" -ForegroundColor Green # Try to get JSON data from Microsoft try { $response = Invoke-WebRequest -Uri $edgeEnterpriseMSIUri -Method Get -ContentType "application/json" -UseBasicParsing -ErrorVariable InvokeWebRequestError $jsonObj = ConvertFrom-Json $([String]::new($response.Content)) Write-Host "Succefully retrived data" -ForegroundColor Green } catch { throw "Could not get MSI data: $InvokeWebRequestError" } # Alternative is to use Invoke-RestMethod to get a Json object directly # $jsonObj = Invoke-RestMethod -Uri "https://edgeupdates.microsoft.com/api/products?view=enterprise" -UseBasicParsing $selectedIndex = [array]::indexof($jsonObj.Product, "$Channel") if (-not $ProductVersion) { try { Write-host "No version specified, getting the latest for $Channel" -ForegroundColor Green $selectedVersion = (([Version[]](($jsonObj[$selectedIndex].Releases | Where-Object { $_.Architecture -eq $Architecture -and $_.Platform -eq $Platform }).ProductVersion) | Sort-Object -Descending)[0]).ToString(4) Write-Host "Latest Version for channel $Channel is $selectedVersion`n" -ForegroundColor Green $selectedObject = $jsonObj[$selectedIndex].Releases | Where-Object { $_.Architecture -eq $Architecture -and $_.Platform -eq $Platform -and $_.ProductVersion -eq $selectedVersion } } catch { throw "Unable to get object from Microsoft. Check your parameters and refer to script help." } } else { Write-Host "Matching $ProductVersion on channel $Channel" -ForegroundColor Green $selectedObject = ($jsonObj[$selectedIndex].Releases | Where-Object { $_.Architecture -eq $Architecture -and $_.Platform -eq $Platform -and $_.ProductVersion -eq $ProductVersion }) if (-not $selectedObject) { throw "No version matching $ProductVersion found in $channel channel for $Architecture architecture." } else { Write-Host "Found matching version`n" -ForegroundColor Green } } if (Test-Path $Folder) { foreach ($artifacts in $selectedObject.Artifacts) { # Not showing the progress bar in Invoke-WebRequest is quite a bit faster than default $ProgressPreference = 'SilentlyContinue' Write-host "Starting download of: $($artifacts.Location)" -ForegroundColor Green # Work out file name $fileName = Split-Path $artifacts.Location -Leaf if (Test-Path "$Folder\$fileName" -ErrorAction SilentlyContinue) { if ($Force) { Write-Host "Force specified. Will attempt to download and overwrite existing file." -ForegroundColor Green try { Invoke-WebRequest -Uri $artifacts.Location -OutFile "$Folder\$fileName" -UseBasicParsing } catch { throw "Attempted to download file, but failed: $error[0]" } } else { # CR-someday: There should be an evaluation of the file version, if possible. Currently the function only # checks if a file of the same name exists, not if the versions differ Write-Host "$Folder\$fileName already exists!" -ForegroundColor Yellow do { $overWrite = Read-Host -Prompt "Press Y to overwrite or N to quit." } # -notmatch is case insensitive while ($overWrite -notmatch '^y$|^n$') if ($overWrite -match '^y$') { Write-Host "Starting Download" -ForegroundColor Green try { Invoke-WebRequest -Uri $artifacts.Location -OutFile "$Folder\$fileName" -UseBasicParsing } catch { throw "Attempted to download file, but failed: $error[0]" } } else { Write-Host "File already exists and user chose not to overwrite, exiting script." -ForegroundColor Red exit } } } else { Write-Host "Starting Download" -ForegroundColor Green try { Invoke-WebRequest -Uri $artifacts.Location -OutFile "$Folder\$fileName" -UseBasicParsing } catch { throw "Attempted to download file, but failed: $error[0]" } } if (((Get-FileHash -Algorithm $artifacts.HashAlgorithm -Path "$Folder\$fileName").Hash) -eq $artifacts.Hash) { Write-Host "Calculated checksum matches known checksum`n" -ForegroundColor Green } else { Write-Warning "Checksum mismatch!" Write-Warning "Expected Hash: $($artifacts.Hash)" Write-Warning "Downloaded file Hash: $((Get-FileHash -Algorithm $($artifacts.HashAlgorithm) -Path "$Folder\$fileName").Hash)`n" } } } Else { throw "Folder $Folder does not exist" } Write-Host "-- Script Completed: File Downloaded -- " -ForegroundColor Green Write-Host "Installing..." -ForegroundColor Green cmd /c start /wait msiexec /i "$Folder\$fileName" /qn /norestart Set-Service edgeupdate -StartupType Manual -ErrorAction SilentlyContinue Set-Service edgeupdatem -StartupType Manual -ErrorAction SilentlyContinue Unregister-ScheduledTask -TaskName MicrosoftEdgeUpdateTaskMachineCore -Confirm:$false -ErrorAction SilentlyContinue Unregister-ScheduledTask -TaskName MicrosoftEdgeUpdateTaskMachineUA -Confirm:$false -ErrorAction SilentlyContinue Write-Host "Installed Microsoft Edge" -ForegroundColor Green