powershell download file from delayed Link - powershell

I'm trying to download a msi Package from a Page which does a redirection in the background which downloads the file I want.
This is the Page I want to download the msi from:
https://remotedesktopmanager.com/de/home/thankyou/rdmmsi
I tried several PowerShell Scripts, but none of them extracted the right download URL or downloaded the file.
With Invoke-Webrequest -Outfile C:xxx only the HTML is saved.

the page uses javascript with a timeout to redirect to the current setup file. that's why you cannot use Invoke-WebRequest as this uses the Internet Explorer engine under the hood which also performs this javascript window.location redirect (resulting in opening the url in the default browser).
To only get the raw HTML you have to use Invoke-RestMethod
$website = Invoke-RestMethod -Uri 'https://remotedesktopmanager.com/de/home/thankyou/rdmmsi'
The full website is now stored in the variable $website without interpreting the javascript.
To find the line with the string window.location i use Select-String which requires a file to be parsed. Thus the content of the variable is first stored in the file which is then parsed.
$tmpFilePath = 'C:\tmp\t.txt'
Out-File -FilePath $tmpFilePath -InputObject $website
$urlRedirectLine = Select-String -Path $tmpFilePath -SimpleMatch "window.location"
Remove-Item -Path $tmpFilePath
The new variable $urlRedirectLine (which content now is C:\tmp\t.txt:999: setTimeout(function () { window.location = 'https://cdn.devolutions.net/download/Setup.RemoteDesktopManager.2021.1.25.0.msi'; }, 4500);) contains the string we are looking for.
To extract that url i convert to variable to string and then use SubString() to extract the url itself. For this i look for the first ' and last ' in that variable.
$urlString = $urlRedirectLine.ToString()
$url = $urlString.Substring($urlString.IndexOf("'")+1,$urlString.LastIndexOf("'")-$urlString.IndexOf("'")-1)
Resulting in $url having the url https://cdn.devolutions.net/download/Setup.RemoteDesktopManager.2021.1.25.0.msi
To download the file you can again use Invoke-RestMethod
Invoke-RestMethod -Uri $url -OutFile 'C:\tmp\rdm.msi'

I was facing similar error while trying to download httpd.
Following worked for me (-UserAgent "NativeHost")
$ENV:HTTPD_DOWNLOAD_URL = "https://www.apachelounge.com/download/VS16/binaries/httpd-2.4.52-win64-VS16.zip"
$ENV:HTTPD_DOWNLOAD_ZIP = "httpd.zip"
Invoke-WebRequest -Uri $ENV:HTTPD_DOWNLOAD_URL -OutFile $ENV:HTTPD_DOWNLOAD_ZIP -UserAgent "NativeHost";
Reference
https://social.technet.microsoft.com/Forums/en-US/23fccc30-5f84-4a84-8160-c6e95102b11c/powershell-invokewebrequest-sourceforge-urlsredirectiondynamic-content?forum=winserverpowershell

The Link you give is of main download page which redirects after few second to the download.
The downloading link is "https://cdn.devolutions.net/download/Setup.RemoteDesktopManager.2021.1.25.0.msi"
Use the following command to download that MSI.
$url = "https://cdn.devolutions.net/download/Setup.RemoteDesktopManager.2021.1.25.0.msi"
$dest = "C:\Setup.RemoteDesktopManager.2021.1.25.0.msi"
Start-BitsTransfer -Source $url -Destination $dest
You can also use Invoke-WebRequest using the above variable
Invoke-WebRequest -Uri $url -OutFile $dest
Thank You

Related

PowerShell, Invoke-WebRequest for a url that is not pointing at a file, but initiates a file download

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
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:
Download the file as if I clicked on the link on the download page?
Get the name of the file that is downloaded (as I see that the full file version is in the file downloaded)?
Redirect that download to a destination of my choosing?
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])"
}
}
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."

PowerShell - downloads TXT file with WRONG content using the REST API

I have a file which I download using the REST API.
Just to emphasize that I tried with both commands: Invoke-RestMethod and Invoke-WebRequest
$uri = "https://bitbucket.org.dev/projects/TEST/repos/fa/browse/Packages/ATS.txt"
$API_KEY="ZTU2MT"
Invoke-WebRequest -Headers #{Authorization=$("Basic {0}" -f $API_KEY)} -Uri $uri -OutFile ATS.txt
If I access that URI in browser file or download it manually file can be viewd without any issue in clear way.
This is the content of the file (its begining)
#
# exported extension module.
# source ""
# timestamp (utc) "2020-03-30 12:06:23.3"
# ***** DO NOT EDIT! *****
But download file looks completely different (like it is in HTML format)
<!DOCTYPE html><html lang="en"><head><meta charset="utf-8"><meta http-equiv="X-..."
Also I have some zip file which needs to be downloaded as well, but with it also I am getting invalid file which cannot be extracted (opened)
As written in MSDN, Invoke-WebRequest returns an object of type BasicHtmlWebResponseObject.
You need to select the Content property to get the text you are looking for.
Invoke-WebRequest -Headers #{Authorization=$("Basic {0}" -f $API_KEY)} -Uri $uri | Select-Object -Expand Content | Out-File -FilePath c:\somefile.txt
Update:
Check this post to find more info about downloading files from a private repository in BitBucket.
https://stackoverflow.com/a/50222671/13440610

download openBLAS from SourceForge using PowerShell

I would like to use PowerShell to download openBLAS from SourceForge. My problem is that the PS documentation I have read always refers to a specific file name, but, when I submit that request, SF redirects it to /download, and something happens, but I don't get what I am looking for. Here is the current code:
$url = 'https://sourceforge.net/projects/openblas/files/v0.3.6/OpenBLAS-0.3.6-x64.zip'
# $url = 'https://sourceforge.net/projects/openblas/files/v0.3.6/OpenBLAS-0.3.6-x64.zip/download'
$output = 'C:\BLAS\OpenBLAS-0.3.6-x64.zip'
Invoke-WebRequest $url -OutFile $output
It works for me in Windows 10 PowerShell 5.1.
Invoke-WebRequest -Uri $url -OutFile $path -UserAgent [Microsoft.PowerShell.Commands.PSUserAgent]::FireFox
source

Downloading a file with PowerShell

I have a URL to a CSV file which, in a browser, I can download and open without issue.
I'm trying to download this file using PowerShell without success. I tried using Invoke-WebRequest, Start-BitsTransfer and using a webrequest object but no luck there.
Invoke-WebRequest comes with a parameter to store its result in a file: -OutFile
Invoke-WebRequest $myDownloadUrl -OutFile c:\file.ext
If you need authorization before you can send a request like this:
Invoke-WebRequest $myAuthUrl /* whatever is neccesary to login */ -SessionVariable MySession
Invoke-WebRequest $myDownloadUrl -WebSession $MySession
To determine the layout of the form where the login happens, you can use Invoke-WebRequests return object. It'll collect information about forms and fields on the HTML (might be Windows only). Mileage of logging in may vary with things like Two-Factor-Auth active or not. Probably you can create some secret link to your file which does not need Auth or possibly google allows you to create a private access token of some sort, which can be send aus Authorization-Header alongside your request.
TLDR answers*:
Method 1, by default synchronous**
Invoke-WebRequest $url -OutFile $path_to_file
(if you get error "...Could not create SSL/TLS secure channel." see Powershell Invoke-WebRequest Fails with SSL/TLS Secure Channel)
Method 2, by default synchronous**
(New-Object System.Net.WebClient).DownloadFile($url, $path_to_file)
Method 3, asynchronous and may be much slower than the other two but is very gentle on bandwidth usage (it uses the BITS service).
Import-Module BitsTransfer
Start-BitsTransfer -Source $url -Destination $path_to_file
Notes:
*: This answer is for those that google for "how to download a file with PowerShell".
**: Read the help pages if you want asynchronous downloading
For a while now I've been using a PS script to download PowerBI bi-monthly and using the BITS, it's been pretty solid and now so much stronger now since I removed the -Asynchronous at the end of the Start-BitsTransfer
$url = "https://download.microsoft.com/download/8/8/0/880BCA75-79DD-466A-927D-1ABF1F5454B0/PBIDesktopSetup.exe"
$output = "%RandomPath%\PowerBI Pro\PBIDesktopSetup.exe"
$start_time = Get-Date
Import-Module BitsTransfer
Start-BitsTransfer -Source $url -Destination $output
#Commented out below because it kept creating "Tmp files"
#Start-BitsTransfer -Source $url -Destination $output -Asynchronous

PowerShell Invoke-WebRequest, how to automatically use original file name?

How can I use Invoke-WebRequest to download a file but automatically make the file name the same as if I downloaded via browser? I haven't found a way to make -OutFile work without manually specifying the file name. I'm fine with this involving a few other lines of code.
A good solution will:
Work even if the file name isn't in the request URL. For example, the URL to download the Visual Studio x64 Remote Debugging Tools is http://go.microsoft.com/fwlink/?LinkId=393217 but it downloads the file rtools_setup_x64.exe.
Not save the whole file to memory before writing to disk, unless that's what Invoke-WebRequest already does even with the -OutFile parameter (?)
Thanks!
For the example given you're going to need to get the redirected URL, which includes the file name to be downloaded. You can use the following function to do so:
Function Get-RedirectedUrl {
Param (
[Parameter(Mandatory=$true)]
[String]$URL
)
$request = [System.Net.WebRequest]::Create($url)
$request.AllowAutoRedirect=$false
$response=$request.GetResponse()
If ($response.StatusCode -eq "Found")
{
$response.GetResponseHeader("Location")
}
}
Then it's a matter of parsing the file name from the end of the responding URL (GetFileName from System.IO.Path will do that):
$FileName = [System.IO.Path]::GetFileName((Get-RedirectedUrl "http://go.microsoft.com/fwlink/?LinkId=393217"))
That will leave $FileName = rtools_setup_x64.exe and you should be able to download your file from there.
Try this method (may not always work because the file name may not be in the response header)
call Invoke-WebRequest to get the result. then you can inspect the result to look at what is in the headers.
get the file name from the response header (this could be in Headers.Location, or some other place. When I run my query for a url that i was troubleshooting, I found it in the Headers["Content-Disposition"] and it looks like inline; filename="zzzz.docx"
Create a new file based on the name and write the content to this file
Here is code sampe:
$result = Invoke-WebRequest -Method GET -Uri $url -Headers $headers
$contentDisposition = $result.Headers.'Content-Disposition'
$fileName = $contentDisposition.Split("=")[1].Replace("`"","")
$path = Join-Path $yourfoldername $fileName
$file = [System.IO.FileStream]::new($path, [System.IO.FileMode]::Create)
$file.write($result.Content, 0, $result.RawContentLength)
$file.close()
Thanks to Ryan I have a semi-usable function:
Function Get-Url {
param ( [parameter(position=0)]$uri )
invoke-webrequest -uri "$uri" -outfile $(split-path -path "$uri" -leaf)
}
A graphic file and xml file I have been able to download. When I try to download this webpage and open it with Edge it will work at times.
Essence of my code - this works.. using PS 5.1
I have commented out the normal -Outfile statement because that would imply I knew the filename in advance.
I have put this together based upon a number of sources, there are lots of ways of parsing the Content-Disposition headers so use whatever works for you.
$outpath = "C:\\temp\\"
The call:
$result = Invoke-WebRequest -method GET -Uri $resourceUrl -Headers
$resourceHeaders -Verbose #-OutFile $($outPath+"$nodeId.pdf")
parsing
$outFilename = $outpath+$result.Headers.'Content-Disposition'.Split("=")[1].Split('\\""')[1] #shaky parsing - might require improvement in time
Writing the file (this is mostly pdf's for me
[System.IO.File]::WriteAllBytes($outFilename, $result.content)
powershell.exe Invoke-WebRequest -Uri serverIP/file.exe -OutFile C:\Users\file.exe