Search code examples
powershellx509certificatepowershell-4.0

Accept certificate permanently during FtpWebRequest via PowerShell


Recently I encounter some problems making the connection to a FTP server but there will be some popup asking for the acceptance on the certificate.

I don't know how to overcome this via PowerShell during invoke method $ftpRequest.GetResponse(). I found some solution regarding overriding the callback method on certificate like this one [System.Net.ServicePointManager]::ServerCertificateValidationCallback

The solution is given on C# & I don't know how to port it to PowerShell yet.

My code is as below

function Create-FtpDirectory {
    param(
        [Parameter(Mandatory=$true)]
        [string]
        $sourceuri,
        [Parameter(Mandatory=$true)]
        [string]
        $username,
        [Parameter(Mandatory=$true)]
        [string]
        $password
    )
    if ($sourceUri -match '\\$|\\\w+$') { throw 'sourceuri should end with a file name' }
    $ftprequest = [System.Net.FtpWebRequest]::Create($sourceuri);    

    Write-Information -MessageData "Create folder  to store backup (Get-FolderName -Path $global:backupFolder)"
    $ftprequest.Method = [System.Net.WebRequestMethods+Ftp]::MakeDirectory
    $ftprequest.UseBinary = $true

    $ftprequest.Credentials = New-Object System.Net.NetworkCredential($username,$password)
    $ftprequest.EnableSsl = $true        

    $response = $ftprequest.GetResponse();

    Write-Host "Folder created successfully, status $response.StatusDescription"

    $response.Close();
}

Solution

  • It's a bit hacky, but you can use raw C# in PowerShell via Add-Type. Here's an example class I've used to be able to toggle certificate validation in the current PowerShell session.

    if (-not ([System.Management.Automation.PSTypeName]'CertValidation').Type)
    {
        Add-Type @"
            using System.Net;
            using System.Net.Security;
            using System.Security.Cryptography.X509Certificates;
            public class CertValidation
            {
                static bool IgnoreValidation(object o, X509Certificate c, X509Chain ch, SslPolicyErrors e) {
                    return true;
                }
                public static void Ignore() {
                    ServicePointManager.ServerCertificateValidationCallback = IgnoreValidation;
                }
                public static void Restore() {
                    ServicePointManager.ServerCertificateValidationCallback = null;
                }
            }
    "@
    }
    

    Then you can use it prior to calling your function like this.

    [CertValidation]::Ignore()
    

    And later, restore default cert validation like this.

    [CertValidation]::Restore()
    

    Keep in mind though that it's much safer to just fix your service's certificate so that validation actually succeeds. Ignoring certificate validation should be your last resort if you have no control over the environment.