Public/Network/FTP/Get-FtpFile.ps1
# this could be cleaned up with http://learn-powershell.net/2013/02/08/powershell-and-events-object-events/ # learn from: function Get-FtpFile { <# .SYNOPSIS Downloads a file from a File Transfter Protocol (FTP) location. .DESCRIPTION This will download a file from an FTP location, saving the file to the FileName location specified. .NOTES This is a low-level function and not recommended for use in package scripts. It is recommended you call `Get-ChocolateyWebFile` instead. Starting in 0.9.10, will automatically call Set-PowerShellExitCode to set the package exit code to 404 if the resource is not found. .INPUTS None .OUTPUTS None .PARAMETER Url This is the url to download the file from. .PARAMETER FileName This is the full path to the file to create. If FTPing to the package folder next to the install script, the path will be like `"$(Split-Path -Parent $MyInvocation.MyCommand.Definition)\\file.exe"` .PARAMETER UserName The user account to connect to FTP with. .PARAMETER Password The password for the user account on the FTP server. .PARAMETER Quiet Silences the progress output. .PARAMETER IgnoredArguments Allows splatting with arguments that do not apply. Do not use directly. .LINK Get-ChocolateyWebFile .LINK Get-WebFile #> param( [parameter(Mandatory = $false, Position = 0)][string] $url = '', [parameter(Mandatory = $true, Position = 1)][string] $fileName = $null, [parameter(Mandatory = $false, Position = 2)][string] $username = $null, [parameter(Mandatory = $false, Position = 3)][SecureString] $password = $null, [parameter(Mandatory = $false)][switch] $quiet, [parameter(ValueFromRemainingArguments = $true)][Object[]] $ignoredArguments ) # Log Invocation and Parameters used. $MyInvocation, $PSBoundParameters if ($url -eq $null -or $url -eq '') { Write-Warning "Url parameter is empty, Get-FtpFile has nothing to do." return } if ($fileName -eq $null -or $fileName -eq '') { Write-Warning "FileName parameter is empty, Get-FtpFile cannot save the output." return } try { $uri = [System.Uri]$url if ($uri.IsFile()) { Write-Debug "Url is local file, setting destination" if ($url.LocalPath -ne $fileName) { Copy-Item $uri.LocalPath -Destination $fileName -Force } return } } catch { $null } # Create a FTPWebRequest object to handle the connection to the ftp server $ftprequest = [System.Net.FtpWebRequest]::create($url) # check if a proxy is required $explicitProxy = $env:dotfilesProxyLocation $explicitProxyUser = $env:dotfilesProxyUser $explicitProxyPassword = $env:dotfilesProxyPassword $explicitProxyBypassList = $env:dotfilesProxyBypassList $explicitProxyBypassOnLocal = $env:dotfilesProxyBypassOnLocal if ($null -ne $explicitProxy) { # explicit proxy $proxy = New-Object System.Net.WebProxy($explicitProxy, $true) if ($null -ne $explicitProxyPassword) { $passwd = ConvertTo-SecureString $explicitProxyPassword $proxy.Credentials = New-Object System.Management.Automation.PSCredential ($explicitProxyUser, $passwd) } if ($null -ne $explicitProxyBypassList -and $explicitProxyBypassList -ne '') { $proxy.BypassList = $explicitProxyBypassList.Split(',', [System.StringSplitOptions]::RemoveEmptyEntries) } if ($explicitProxyBypassOnLocal -eq 'true') { $proxy.BypassProxyOnLocal = $true; } Write-Info "Using explicit proxy server '$explicitProxy'." $ftprequest.Proxy = $proxy } # set the request's network credentials for an authenticated connection $ftprequest.Credentials = New-Object System.Net.NetworkCredential($username, $password) $ftprequest.Method = [System.Net.WebRequestMethods+Ftp]::DownloadFile $ftprequest.UseBinary = $true $ftprequest.KeepAlive = $false # use the default request timeout of 100000 if ($null -ne $env:dotfilesRequestTimeout -and $env:dotfilesRequestTimeout -ne '') { $ftprequest.Timeout = $env:dotfilesRequestTimeout } if ($null -ne $env:dotfilesResponseTimeout -and $env:dotfilesResponseTimeout -ne '') { $ftprequest.ReadWriteTimeout = $env:dotfilesResponseTimeout } try { # send the ftp request to the server $ftpresponse = $ftprequest.GetResponse() [long]$goal = $ftpresponse.ContentLength $goalFormatted = Format-ItemSize $goal # get a download stream from the server response $reader = $ftpresponse.GetResponseStream() # create the target file on the local system and the download buffer $writer = New-Object IO.FileStream ($fileName, [IO.FileMode]::Create) [byte[]]$buffer = New-Object byte[] 1048576 [long]$total = [long]$count = 0 $OgEAP = $ErrorActionPreference $ErrorActionPreference = 'Stop' try { # loop through the download stream and send the data to the target file do { $count = $reader.Read($buffer, 0, $buffer.Length); $writer.Write($buffer, 0, $count); if (!$quiet) { $total += $count $totalFormatted = Format-ItemSize $total if ($goal -gt 0) { $percentComplete = [Math]::Truncate(($total / $goal) * 100) Write-Progress "Downloading $url to $fileName" "Saving $totalFormatted of $goalFormatted ($total/$goal)" -Id 0 -PercentComplete $percentComplete } else { Write-Progress "Downloading $url to $fileName" "Saving $total bytes..." -Id 0 -Completed } if ($total -eq $goal -and $count -eq 0) { Write-Progress "Completed download of $url." "Completed a total of $total bytes of $fileName" -Id 0 -Completed -PercentComplete 100 } } } while ($count -ne 0) Write-Info "" Write-Info "Download of $([System.IO.Path]::GetFileName($fileName)) ($goalFormatted) completed." } finally { $ErrorActionPreference = $OgEAP } $writer.Flush() # closed in finally block } catch { if ($null -ne $ftprequest) { $ftprequest.ServicePoint.MaxIdleTime = 0 $ftprequest.Abort(); # ruthlessly remove $ftprequest to ensure it isn't reused Remove-Variable ftprequest Start-Sleep 1 [System.GC]::Collect() } Set-PowerShellExitCode 404 if ($env:DownloadCacheAvailable -eq 'true') { throw "The remote file either doesn't exist, is unauthorized, or is forbidden for url '$url'. $($_.Exception.Message) `nThis package is likely not broken for licensed users - see https://docs.chocolatey.org/en-us/features/private-cdn." } else { throw "The remote file either doesn't exist, is unauthorized, or is forbidden for url '$url'. $($_.Exception.Message)" } } finally { if ($null -ne $reader) { try { $reader.Close(); } catch { $null } } if ($null -ne $writer) { try { $writer.Close(); } catch { $null } } if ($null -ne $ftpresponse) { try { $ftpresponse.Close(); } catch { $null } } Start-Sleep 1 } } |