Version 2:
# downloadFilesViaSftp.ps1
# Version 0.0.2
#
# Description:
# This simple script is to download files from a remote Linux server via SFTP
#
# Features:
# 1. Connect to remote SFTP server and verify contents prior to downloading
# 2. Translate Unix/Linux line-feed (LF) characters to carriage-returns (CRLF) in text files for Windows/ASP.net compatiblity
# 3. Send email notifictions to inform recipients of successful or failed downloads
# Environmental variables
$sftpHost='sftp.kimconnect.com'
$portNumber=22
$sftpUsername='test'
$sftpPassword='password'
$sshHostKey='ssh-rsa 4096 11:22:33:44:55:aa:bb:cc:dd:ee...'
$localDirectory='D:\Downloads'
$remoteDirectory='/home/test/edi'
$winScpAssembly='C:\Program Files (x86)\WinSCP\WinSCPnet.dll'
# Email relay parameters
$emailFrom='[email protected]'
$emailTo='[email protected]'
$subject='EDI File Downloads'
$smtpRelayServer='relay.kimconnect.com'
# Sanitize inputs
$localDirectory=if($localDirectory[$localDirectory.Length-1] -eq '*'){
$localDirectory.Substring(0,$localDirectory.Length-1)
}elseif($localDirectory[$localDirectory.Length-1] -ne '\'){
$localDirectory+'\'
}else{
$localDirectory
}
$remoteDirectory=if($remoteDirectory[$remoteDirectory.Length-1] -eq '*'){
$remoteDirectory.Substring(0,$remoteDirectory.Length-1)
}elseif($remoteDirectory[$remoteDirectory.Length-1] -ne '/'){
$remoteDirectory+'/'
}else{
$remoteDirectory
}
function downloadFilesViaSftp{
param(
[string]$sftpHost='sftp.kimconnect.com',
[int]$portNumber=22,
[string]$sftpUsername='test',
[string]$sftpPassword='password',
[string]$sshHostKey='ssh-rsa 4096 11:22:33:44:55:aa:bb:cc:dd:ee...',
[string]$localDirectory='D:\Downloads',
[string]$remoteDirectory='/home/test/edi',
[string]$winScpAssembly='C:\ProgramData\chocolatey\bin\WinSCPnet.dll'
)
function formatTextFileWindowsCompatible{
param(
$file,
$regexMatch="(?<!\r)\n$",
$replaceWith="`r`n"
)
if([IO.Path]::GetExtension($file) -ne '.txt'){
break
}else{
$content=get-content $file
$newContent=$content|%{$_.Replace($regexMatch,$replaceWith)}
[System.IO.File]::WriteAllText($file,$($newContent|out-string))
}
}
try{
Add-Type -Path $winScpAssembly # Load WinSCP .NET assembly into this session
$sessionOptions = New-Object WinSCP.SessionOptions -Property @{
Protocol = [WinSCP.Protocol]::Sftp
HostName = $sftpHost
PortNumber = $portNumber
UserName = $sftpUsername
Password = $sftpPassword
SshHostKeyFingerprint = $sshHostKey
}
$session = New-Object WinSCP.Session
$session.Open($sessionOptions)
}catch{
write-warning $_
return $false
}
if($session){
Try{
if(!(test-path $localDirectory)) {
new-item -Path $localDirectory -Type Directory -Force
}
# Checking whether there are 0 bytes files that would cause GetFiles method to freeze
$downloadedFiles=$emptyFiles=$filesToDownload=@()
$listDirectory = $session.ListDirectory($remoteDirectory)
foreach ($file in $listDirectory.Files){
if($file.Length){
Write-Host ("{0}{1} {2,9} {3,-12:MMM dd HH:mm:ss yyyy} {4}" -f
$file.FileType, $fileInfo.FilePermissions, $file.Length,
$file.LastWriteTime, $file.Name)
$filesToDownload+=$file.Name
}elseif($file.Name -ne '..'){
Write-Host ("{0}{1} {2,9} {3,-12:MMM dd HH:mm:ss yyyy} {4}" -f
$file.FileType, $fileInfo.FilePermissions, $file.Length,
$file.LastWriteTime, $file.Name) -ForegroundColor Red
$emptyFiles+=$file.Name
}
}
if($filesToDownload){
$transferOptions = New-Object WinSCP.TransferOptions
$transferOptions.TransferMode = [WinSCP.TransferMode]::Binary
foreach ($fileName in $filesToDownload){
$transferResult=$session.GetFiles($RemoteDirectory+$fileName,$localDirectory,$False,$transferOptions)
if($transferResult.Transfers.count -gt 0){
Write-Host "Download of $($transferResult.FileName) succeeded" -ForegroundColor Green
$downloadedFile=$([IO.Path]::Combine($localDirectory,$fileName))
$downloadedFiles+=$downloadedFile
fixFile $downloadedFile
}else{
Write-Host "Download of $fileName failed" -ForegroundColor Red
}
}
}else{
write-host "There are no files to download."
}
# $fileNames=$session.ListDirectory($remoteDirectory).Files.Name|?{$_ -ne '..'}
# $destinationFiles=$fileNames|%{[IO.Path]::Combine($localDirectory,$_)}
# $transferOptions = New-Object WinSCP.TransferOptions
# $transferOptions.TransferMode = [WinSCP.TransferMode]::Binary
# $transferResult=$session.GetFiles($RemoteDirectory+'*',$localDirectory,$False,$transferOptions)
# if($transferResult.Transfers.count -gt 0){
# foreach ($transfer in $transferResult.Transfers){
# Write-Host "Download of $($transfer.FileName) succeeded"
# }
# }
# $destinationFiles|%{formatTextFileWindowsCompatible $_}
return [pscustomobject]@{
downloadedFiles=$downloadedFiles
emptyFiles=$emptyFiles
}
}Catch{
write-warning $_
$result=$false
}finally{
$session.Dispose()
}
return $result
}
}
$result=downloadFilesViaSftp -sftpHost $sftpHost `
-portNumber $portNumber `
-sftpUsername $sftpUsername `
-sftpPassword $sftpPassword `
-sshHostKey $sshHostKey `
-localDirectory $localDirectory `
-remoteDirectory $remoteDirectory `
-winScpAssembly $winScpAssembly
if($result){
$emailContent="Good day $emailTo,<br><br>As of $((get-date|out-string).trim())<br><br>"
$emailContent+=if($result.downloadedFiles){
"These new files have successfully downloaded:<br>$(($result.downloadedFiles|out-string).trim())<br>"
}else{
"No files have been downloaded.<br>"
}
$emailContent+=if($result.emptyFiles){
"These files have no contents and are not downloaded:<br>$(($result.emptyFiles|out-string).trim())<br><br>Please double check with the source."
}else{''}
Send-MailMessage -From $emailFrom `
-To $emailTo `
-Subject $subject `
-Body $emailContent `
-BodyAsHtml `
-SmtpServer $smtpRelayServer
}
Version 1:
# downloadFilesViaSftp.ps1
# Version 0.0.1
# This simple script is to download files from a remote Linux server via SFTP
# There's a special sequence to handle .txt files
# by replacing Linux line-feed 'lf' chars with their Windows carriage-return line-feed 'crlf' equivalence
# Environmental variables
$sftpHost='sftp.kimconnect.com'
$portNumber=22
$sftpUsername='test'
$sftpPassword='password'
$sshHostKey='ssh-rsa 4096 11:22:33:44:55:aa:bb:cc:dd:ee...'
$localDirectory='D:\Downloads'
$remoteDirectory='/home/test/edi'
$winScpAssembly='C:\Program Files (x86)\WinSCP\WinSCPnet.dll'
function downloadFilesViaSftp{
param(
$sftpHost='sftp.kimconnect.com',
$portNumber=22,
$sftpUsername='test',
$sftpPassword='password',
$sshHostKey='ssh-rsa 4096 11:22:33:44:55:aa:bb:cc:dd:ee...',
$localDirectory='D:\Downloads',
$remoteDirectory='/home/test/edi',
$winScpAssembly='C:\ProgramData\chocolatey\bin\WinSCPnet.dll'
)
function formatTextFileWindowsCompatible{
param(
$file,
$regexMatch="(?<!\r)\n$",
$replaceWith="`r`n"
)
if([IO.Path]::GetExtension($file) -ne '.txt'){
break
}else{
$content=get-content $file
$newContent=$content|%{$_.Replace($regexMatch,$replaceWith)}
[System.IO.File]::WriteAllText($file,$($newContent|out-string))
}
}
try{
Add-Type -Path $winScpAssembly # Load WinSCP .NET assembly into this session
$sessionOptions = New-Object WinSCP.SessionOptions -Property @{
Protocol = [WinSCP.Protocol]::Sftp
HostName = $sftpHost
PortNumber = $portNumber
UserName = $sftpUsername
Password = $sftpPassword
SshHostKeyFingerprint = $sshHostKey
}
$session = New-Object WinSCP.Session
$session.Open($sessionOptions)
}catch{
write-warning $_
return $false
}
if($session){
Try{
if(!(test-path $localDirectory)) {
new-item -Path $localDirectory -Type Directory -Force
}
$fileNames = $session.ListDirectory($remoteDirectory).Files.Name
$destinationFiles=$fileNames|%{[IO.Path]::Combine($localDirectory,$_)}
$transferOptions = New-Object WinSCP.TransferOptions
$transferOptions.TransferMode = [WinSCP.TransferMode]::Binary
$session.GetFiles($remoteDirectory,$localDirectory,$False,$transferOptions)
$destinationFiles|%{formatTextFileWindowsCompatible $_}
$result=$true
}Catch{
write-warning $_
$result=$false
}finally{
$session.Dispose()
}
return $result
}
}
downloadFilesViaSftp -sftpHost $sftpHost `
-portNumber $portNumber `
-sftpUsername $sftpUsername `
-sftpPassword $sftpPassword `
-sshHostKey $sshHostKey `
-localDirectory $localDirectory `
-remoteDirectory $remoteDirectory `
-winScpAssembly $winScpAssembly
Categories:
Subodh
The script is not working and giving error – WARNING: The value supplied is not valid, or the property is read-only. Change the value, and then try again.
kimconnect
Hi Subodh, this script has only been tested in a controlled environment (a ‘jump box’). Without knowing or having access to your environment, it’s difficult to know which line of script is throwing the error. Please play around with the variables and let me know if you would like to provide more info. Also, if you’ve fixed an error in script, I’d be appreciative of your sharing.
Nicola
Also for me the same error.
If you have news just let me know.
Thansk
kimconnect
Hi Nicola, could it be that this script must be ran in the context of a System Administrator? Please run PowerShell as System Administrator and paste script (after updating the static variables at the top of script). Let me know if we’re still experience issues. Also, paste some error messages so that I can see which line is causing errors. Thanks