Home > Net >  PowerShell, Invoke-WebRequest for a url that is not pointing at a file, but initiates a file downloa
PowerShell, Invoke-WebRequest for a url that is not pointing at a file, but initiates a file downloa

Time:11-07

I can download the Google Chrome installer easily as follows:

Invoke-WebRequest "http://dl.google.com/chrome/install/latest/chrome_installer.exe" -OutFile "$env:Temp\chrome_installer.exe"

However, for Opera, I want specifically the latest 64-bit version. On the download page at https://www.opera.com/download there is a handy link to that:

https://download.opera.com/download/get/?partner=www&opsys=Windows&arch=x64

enter image description here

When I click on the "64 bit" link, it automatically starts the download of the latest executable, but using Invoke-WebRequest on that url does not download the file:

Invoke-WebRequest "https://download.opera.com/download/get/?partner=www&opsys=Windows&arch=x64" -OutFile "$env:Temp\opera_installer.exe"

How can I manipulate a url like this to:

  1. Download the file as if I clicked on the link on the download page?
  2. Get the name of the file that is downloaded (as I see that the full file version is in the file downloaded)?
  3. Redirect that download to a destination of my choosing?

CodePudding user response:

To access the installers you could use the following URI:

https://get.opera.com/pub/opera/desktop/

Depending on the version you want you can do:

Invoke-WebRequest "https://get.opera.com/pub/opera/desktop/92.0.4561.43/win/Opera_92.0.4561.43_Setup_x64.exe" -OutFile "$env:Temp\opera_installer.exe"

Working with link mentioned above you could do something like this:

#Set source URI
$uri = "https://get.opera.com/pub/opera/desktop/"

#As the links are sorted by version the last link is the newest version
(Invoke-WebRequest -uri $uri).links[-1] | %{
    #Parse string to link and as we want the Windows version add 'win/', filter for 'Setup_x64\.exe$'
    $uri = [Uri]::new([Uri]$uri, $_.href).AbsoluteUri   'win/'
    (Invoke-WebRequest $uri).links | ?{$_.href -match 'Setup_x64\.exe$'} | %{
        #Build new Uri, download file and write it to disk
        $uri = [Uri]::new([Uri]$uri, $_.href)
        Invoke-WebRequest -Uri $uri -OutFile "C:\tmp\$($uri.Segments[-1])"
    }
}

CodePudding user response:

It looks like the download URL you found isn't just a chain of straight redirects but involves a JavaScript file that dynamically builds the ultimate target URL, so Invoke-WebRequest cannot be used with it.

However, building on Toni's helpful answer, you can do some - simple - web scraping to determine the latest version number and to derive the download URL from it:

$VerbosePreference = 'Continue'

$downloadRootUrl = 'https://get.opera.com/pub/opera/desktop/'
$downloadTargetFile = 'Opera_Setup.exe' 

# Get the version listing and match the *last* <a> element's href attribute,
# assumed to contain the latest version number.
Write-Verbose "Determining latest version via $downloadRootUrl..."
if ((Invoke-RestMethod $downloadRootUrl) -notmatch '(?s)^. <a href="([^/"] ). $') {
  throw "Could not determine latest version."
}

# Extract the version number, via the automatic $Matches variable.
$latestVersion = $Matches[1]

# Construct the full download URI based on the version number.
$downloadUrl = $downloadRootUrl   ('{0}/win/Opera_{0}_Setup_x64.exe' -f $latestVersion)

Write-Verbose "Downloading installer from $downloadUrl..."
& {
  # Temporarily silence the progress stream, because in Windows PowerShell 
  # its display slows things down significantly.
  $ProgressPreference = 'SilentlyContinue'
  try {
    Invoke-RestMethod -ErrorAction Stop -OutFile $downloadTargetFile $downloadUrl
  } catch {
    throw $_
  }
}

Write-Verbose "Installer for version $latestVersion successfully downloaded to $downloadTargetFile."
  • Related