Unable to download files from a server with unverified certificate

249 views Asked by At

I am trying to download some files from a website that doesn't have a verified SSL certificate. I have used the method explained here to ignore the SSL warning: Ignore SSL warning with powershell downloadstring

###################### Download ###################### 
## download zipped files from WebPage/download (No Valid SSL Certificate)
$myDownloadUrl = 'www.SomeWebPage.com/Download/MyFiles.zip'

## installation folder (always under %appdata%\Company\MyFolder)
$myZipFile = "MyFiles.zip"
$installdir = "\Company\MyFolder\"
$myInstallDir = -join @($env:APPDATA, $installdir)
$myFilePath = -join@($myInstallDir, $myZipFile)

## make sure the folder exists
New-Item -ItemType Directory -Force -Path $myInstallDir

## Skip certificate
$code= @"
        using System.Net;
        using System.Security.Cryptography.X509Certificates;
        public class TrustAllCertsPolicy : ICertificatePolicy {
            public bool CheckValidationResult(ServicePoint srvPoint, X509Certificate certificate, WebRequest request, int certificateProblem) {
                return true;
            }
        }
"@
Add-Type -TypeDefinition $code -Language CSharp
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy

echo ">> Downloading the Files..."
Invoke-WebRequest -Uri $myDownloadUrl -OutFile $myFilePath
Start-Sleep -s 2

This works as intended most of the times. However, sometimes it returns an error:

ERROR: Unable to  read data from the transport connection: An existing connection was forcibly closed by the remote host.
ERROR: Exception calling ".ctor" with "3" argument(s): "End of Central Directory record could not be found."

I tried adding something like this to my script, but the issue persisted. I still may get an error once but not the other time. (Source: Invoke-WebRequest SSL fails?)

$AllProtocols = [System.Net.SecurityProtocolType]'Tls,Tls11,Tls12'
[System.Net.ServicePointManager]::SecurityProtocol = $AllProtocols

Can I do a try-catch routine to make sure the file was downloaded properly before proceeding?

Here's an overview summary of that server

2

There are 2 answers

0
M-- On BEST ANSWER

As I explained above, downloading the files sometimes has no issues and sometimes fails. So, I added a try-catch to keep trying until it's successful. This is based on this thread: Catching FULL exception message

I am not sure what's causing this issue, and would consider this to be a workaround rather than a solution.

## set ErrorActionPreference to stop
$ErrorActionPreferenceBak = $ErrorActionPreference
$ErrorActionPreference    = 'Stop'

While($True){
    try{
        ## downloading the files
        Invoke-WebRequest -Uri $myDownloadUrl -OutFile $myFilePath
        break
    }
    catch{
        Write-Host "Something failed while downloading the files; trying again"
        Start-Sleep -s 1
    }
    finally{
        ## reset ErrorActionPreference
        $ErrorActionPreference = $ErrorActionPreferenceBak
    }
}
2
suchislife On

This issue might be due to the security protocols used by your PowerShell script. When dealing with websites using outdated or unverified SSL certificates, specifying the security protocols can help. Your proposed solution to specify all protocols (Ssl2, Ssl3, Tls, Tls11, Tls12) is a good approach. However, it's important to note that Ssl2 and Ssl3 are outdated and less secure, and their use is generally discouraged.

Here is an adjusted script incorporating the security protocol setting:

# Define the URL and installation directory
$myDownloadUrl = 'https://www.SomeWebPage.com/Download/MyFiles.zip'
$myZipFile = "MyFiles.zip"
$installdir = "\Company\MyFolder\"
$myInstallDir = Join-Path $env:APPDATA $installdir
$myFilePath = Join-Path $myInstallDir $myZipFile

# Ensure the installation directory exists
New-Item -ItemType Directory -Force -Path $myInstallDir

# Trust all certificates
Add-Type -TypeDefinition @"
    using System.Net;
    using System.Security.Cryptography.X509Certificates;
    public class TrustAllCertsPolicy : ICertificatePolicy {
        public bool CheckValidationResult(ServicePoint srvPoint, X509Certificate certificate, WebRequest request, int certificateProblem) {
            return true;
        }
    }
"@ -Language CSharp
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy

# Set security protocols (excluding outdated protocols for better security)
$SecureProtocols = [System.Net.SecurityProtocolType]'Tls,Tls11,Tls12'
[System.Net.ServicePointManager]::SecurityProtocol = $SecureProtocols

# Download the file
Write-Host ">> Downloading the Files..."
Invoke-WebRequest -Uri $myDownloadUrl -OutFile $myFilePath
Start-Sleep -Seconds 2
  • Security Protocols: The script now explicitly sets the security protocols to Tls, Tls11, Tls12. This ensures compatibility with most servers while maintaining a higher level of security.
  • Path Construction: Used Join-Path for better path construction.
  • Trust Policy: The script retains the trust policy to accept unverified SSL certificates.