Home > Net >  Downloading files with powershell 2.0 on windows 7 - From Microsoft
Downloading files with powershell 2.0 on windows 7 - From Microsoft

Time:08-29

I'm trying to automate the download of MSE definition files from Microsoft using powershell on Win7. I'm looking for a poweshell script that will do this.

I cannot use the Windows Update service or BITS service as both of these are disabled to prevent the OS from automatically downloading updates that break the computer. MSE uses the update service to get new definitions.

I have a script (below) working for regular files hosted using https. E.G. https://www.7-zip.org/a/7z1604.exe

When I use a Microsoft download URL (https://go.microsoft.com/fwlink/?linkid=87341), the script fails with this error:

Exception calling "DownloadFile" with "2" argument(s): "The underlying connecti on was closed: An unexpected error occurred on a send." At C:\temp\run.ps1:9 char:40

Microsoft don't use regular https or ftp file links for some reason. I don't know what sort of link they use, but they don't work with the script below. It's not a https certificate problem either. Files from https sources work just fine:

$url = "https://go.microsoft.com/fwlink/?linkid=87341" 
$path = "C:\temp\update.exe" 
# param([string]$url, [string]$path) 

if(!(Split-Path -parent $path) -or !(Test-Path -pathType Container (Split-Path -parent $path))) { 
$targetFile = Join-Path $pwd (Split-Path -leaf $path) 
} 

(New-Object Net.WebClient).DownloadFile($url, $path) 
$path

I got the above script from this link: Downloading files with powershell 2.0 on windows 7

I'm missing something obvious. Any suggestions appreciated.

Thanks.

CodePudding user response:

This code appears to do the trick:

$download = Invoke-WebRequest -Uri "https://go.microsoft.com/fwlink/?linkid=87341"
$FileName = $download.BaseResponse.ResponseUri.Segments[-1]

$file = [System.IO.FileStream]::new("$PSScriptRoot\$FileName", [System.IO.FileMode]::Create)
$file.Write($download.Content, 0, $download.RawContentLength)
$file.Close()

From Matthew Hodgkins blog, and killingtime's link we get:

$download = Invoke-WebRequest -Uri "https://go.microsoft.com/fwlink/?linkid=87341"

But Hodgkins's code tries to use Content-Disposition, which does not exist in $download. Looking through $download I eventually found that $download.BaseResponse.ResponseUri gives us a Uri. Searching around for getting a filename from a Uri eventually led me to Lee_Dailey's use of Segments[-1], giving us:

$FileName = $download.BaseResponse.ResponseUri.Segments[-1]

As for a file destination, in my case I wanted it to be the same folder as the script, so $PSScriptRoot was used to make a small change to Hodgkins's example.

$file = [System.IO.FileStream]::new("$PSScriptRoot\$FileName", [System.IO.FileMode]::Create)
$file.Write($download.Content, 0, $download.RawContentLength)
$file.Close()

CodePudding user response:

This function, which works in both PS v5.1 and PS v7.2.x, uses Invoke-WebRequest for downloading Microsoft links of the format https://go.microsoft.com/fwlink/?linkid=idNumber by first checking if the file name can be retrieved from Content-Disposition (As described in Matthew Hodgkins blog), and, if that fails, then attempts to extract the file name from BaseResponse by determining its type and extracting the URI from the appropriate location.

If the code fails to determine the file name, it attempts to save the file with the file name Dowloaded.File, but this isn't tested and shouldn't be trusted. Throwing an error is likely.

NOTE: While this does work for the 3 example links in the code, the nature of this code is such that one should expect it to work for some links while failing for others. If anyone finds a failing link, and places it in the comments, I might be able figure how to extract the proper file name and modify the function to deal with it correctly.

function Invoke-WebRequestDownload {
    [OutputType([string])]
    param (
        [Parameter(Mandatory = $true, Position = 0)]
        [string]$Uri,
        [Parameter(Mandatory = $false, Position = 1)]
        [string]$OutFile = "$PSScriptRoot\Downloaded.File"
    )
    $FileDownload = Invoke-WebRequest -Uri $Uri
    $FilePath = [System.IO.Path]::GetDirectoryName($OutFile)
    if(-not $FilePath) {$FilePath = $PSScriptRoot}
    $FileName = $null
    if([bool]$FileDownload.Headers['Content-Disposition']) {
        $FileName = [System.Net.Mime.ContentDisposition]::new($FileDownload.Headers["Content-Disposition"]).FileName
    } else {
        switch ($FileDownload.BaseResponse) {
            {$_ -is [System.Net.HttpWebResponse]} {
                $FileName = $FileDownload.BaseResponse.ResponseUri.Segments[-1]
            }
            {$_ -is [System.Net.Http.HttpResponseMessage]} {
                $FileName = $FileDownload.BaseResponse.RequestMessage.RequestUri.Segments[-1]
            }
            Default {
                $FileName = [System.IO.Path]::GetFileName($OutFile)
            }
        }
    }
    if(-not $FileName) {$FileName = 'Downloaded.File'}
    $FileNamePath = Join-Path -Path $FilePath -ChildPath $FileName
    $File = [System.IO.FileStream]::new($FileNamePath, [System.IO.FileMode]::Create)
    $File.Write($FileDownload.Content, 0, $FileDownload.RawContentLength)
    $File.Close()
    Return $FileNamePath
}
$OutFilePath = Invoke-WebRequestDownload -Uri 'https://go.microsoft.com/fwlink/?linkid=87341'
#$OutFilePath = Invoke-WebRequestDownload -Uri 'http://go.microsoft.com/fwlink/?LinkId=393217'
#$OutFilePath = Invoke-WebRequestDownload -Uri 'https://go.microsoft.com/fwlink/?linkid=2109047&Channel=Stable&language=en&consent=1'
$OutFilePath
  • Related