{"id":815,"date":"2015-04-09T04:58:41","date_gmt":"2015-04-09T04:58:41","guid":{"rendered":"https:\/\/poiseddevelopers.com\/reality-tech\/?p=815"},"modified":"2024-05-13T10:25:11","modified_gmt":"2024-05-13T10:25:11","slug":"migrating-documents-via-sftp","status":"publish","type":"post","link":"https:\/\/poiseddevelopers.com\/reality-tech\/migrating-documents-via-sftp\/","title":{"rendered":"Migrating Documents via SFTP"},"content":{"rendered":"<p>A previous post covered how to programmatically download documents via FTP:\u00a0<a title=\"How to download from FTP programmatically\" href=\"https:\/\/reality-tech.com\/automate-migration-of-ftp-files-to-a-file-share\/\" target=\"_blank\" rel=\"noopener\">How to download from FTP programmatically<\/a><br role=\"presentation\" data-uw-rm-sr=\"\" \/>If FTP over SSL is needed, that\u2019s just a property to enable SSL:<\/p>\n<pre lang=\"php\">$request = [Net.WebRequest]::Create($url)\r\n$request.EnableSsl = $true  #enable SSL\r\n\r\n<\/pre>\n<p>Sometimes there is a need to access and download documents via SFTP. That\u2019s a completely different beast. To do that, I utilize the open source WinSCP. Both the .exe and DLL are needed, and can be co-located with the script.\u00a0 Read more about\u00a0<a title=\"About WinSCP\" href=\"http:\/\/winscp.net\/eng\/docs\/introduction\" target=\"_blank\" rel=\"noopener\" aria-label=\"WinSCP - open in a new tab\" data-uw-rm-ext-link=\"\">WinSCP<\/a>.<\/p>\n<p>In PowerShell, just load the type library:<\/p>\n<pre lang=\"php\">Add-Type -Path \"WinSCPnet.dll\"\r\nThen set up the session. Below I chose to use the actual SSH Host Key Fingerprint:\r\n<\/pre>\n<pre lang=\"php\">$sessionOptions = New-Object WinSCP.SessionOptions\r\n$sessionOptions.Protocol = [WinSCP.Protocol]::Sftp\r\n$sessionOptions.HostName = \"sftp.myDomain.com\"\r\n$sessionOptions.UserName = \"username\"\r\n$sessionOptions.Password = 'password'\r\n$sessionOptions.SshHostKeyFingerprint = \"ssh-rsa 1024 96:9b:ed:1f:66:8b:13:64:c3:ed:11:e0:27:68:62:67\"\r\n<\/pre>\n<p>If you don\u2019t want to bother confirming the crypto key, just set this property instead:<\/p>\n<pre lang=\"php\">$sessionOptions.GiveUpSecurityAndAcceptAnySshHostKey = \"True\"\r\n<\/pre>\n<p>Then create a new session and open it:<\/p>\n<pre lang=\"php\">$session = New-Object WinSCP.Session\r\n$session.Open($sessionOptions)\r\n\r\n<\/pre>\n<p data-uw-rm-sr=\"\">Note $session.output contains all the useful FTP transactions, which you can log.<\/p>\n<p>You also have the option to capture debugging information and set the debugging level:<\/p>\n<pre lang=\"php\">$session.DebugLogPath = \"D:\\plautj\\mypath\"\r\n$session.SessionLogPath = \"D:\\plautj\\mypath2\"\r\n$session.DebugLevel = 1\r\n\r\nOnce the connection is established, use the session to:<br role=\"presentation\" data-uw-rm-sr=\"\" \/>1. Capture the directory listing: $directory = $session.ListDirectory($FTPDir)<br role=\"presentation\" data-uw-rm-sr=\"\" \/>2. Download files: $session.GetFiles($remotePath, $localPath).Check()<br role=\"presentation\" data-uw-rm-sr=\"\" \/>3. Delete files: $session.RemoveFiles($remotePath).Check()<\/pre>\n<p>Below is the full script to connect to SFTP, download all files, and delete them from the FTP Server:<\/p>\n<pre lang=\"php\">$DeleteSource = $true;\r\n $DestLocation = \"\\\\DestinationServer\\Location\\\";\r\n $FTPDir = \"\/USERS\/MyDir\"\r\n #todo\r\n $ok = $true;\r\n \r\n try\r\n {\r\n    $ok = test-path $destLocation;\r\n }\r\n catch\r\n{\r\n    $ok=$false;\r\n    write-host -ForegroundColor darkred \"Failed to reach destination location $($destLocation)\"\r\n}\r\n \r\nif ($ok)\r\n{\r\ntry\r\n{\r\n    # Load WinSCP .NET assembly\r\n    Add-Type -Path \"WinSCPnet.dll\"  # requires script co-located DLL\r\n}\r\ncatch\r\n{\r\n    $ok=$false;\r\n    write-host -ForegroundColor darkred \"Failed to acquire types from the WinSCPnet.dll\"\r\n}\r\n}\r\n \r\n if ($ok)\r\n{\r\n try\r\n {\r\n    # Setup session options\r\n    $sessionOptions = New-Object WinSCP.SessionOptions\r\n    $sessionOptions.Protocol = [WinSCP.Protocol]::Sftp\r\n    $sessionOptions.HostName = \"sftp.SomeDomain.com\"\r\n    $sessionOptions.UserName = \"userID\"\r\n    $sessionOptions.Password = 'Password'\r\n    $sessionOptions.SshHostKeyFingerprint = \"ssh-rsa 1024 96:9b:ed:1f:66:8b:13:64:c3:ed:11:e0:27:68:62:67\"\r\n \r\n    $session = New-Object WinSCP.Session\r\n    $session.Open($sessionOptions)\r\n }\r\n catch\r\n{\r\n    $ok=$false;\r\n    write-host -ForegroundColor darkred \"Failed to open SFTP connection\"\r\n}\r\n}\r\n \r\n if ($ok)\r\n {\r\n    try #to get the directory listing\r\n    {\r\n        $directory = $session.ListDirectory($FTPDir)\r\n    }\r\n    catch\r\n    {\r\n        $ok=$false;\r\n        write-host -ForegroundColor darkred \"Failed to get FTP Directory $($FTPDir)\"\r\n    }\r\n }\r\n \r\n if ($ok)\r\n {\r\n    try # to download each file that is not itself a directory\r\n    {\r\n        foreach ($f in $Directory.Files)\r\n        {\r\n            if (!$f.IsDirectory)\r\n            {\r\n                try\r\n                {\r\n                $RemotePath = \"$($FTPDir)\/$($f.name)\"\r\n                $LocalPath  =  \"$($DestLocation)$($f.name)\"\r\n                $LocalPath  = $LocalPath.trim()\r\n                $session.GetFiles($remotePath, $localPath).Check()\r\n                write-host -ForegroundColor darkgreen \"Deleted file from $($RemotePath) to $($LocalPath)\"\r\n                }\r\n                catch\r\n                {\r\n                    $ok=$false;\r\n                    write-host -ForegroundColor darkred \"Failed to download file from $($RemotePath) to $($LocalPath)\"\r\n                }\r\n \r\n            }\r\n        }\r\n    }\r\n    catch\r\n    {\r\n        $ok=$false;\r\n        write-host -ForegroundColor darkred \"Generic failure Failed to download file from FTP Directory $($FTPDir)\"\r\n    }\r\n \r\n }\r\n \r\nif ($ok)\r\n{\r\n    if ($DeleteSource)\r\n    {\r\n     foreach ($f in $Directory.Files)\r\n        {\r\n            if (!$f.IsDirectory)\r\n            {\r\n                try # try to delete each FTP file that is not a directory\\\r\n                {\r\n                $RemotePath = \"$($FTPDir)\/$($f.name)\"\r\n                $LocalPath  =  \"$($DestLocation)$($f.name)\"\r\n                $LocalPath  = $LocalPath.trim()\r\n                $session.RemoveFiles($remotePath).Check()\r\n                write-host -ForegroundColor darkgreen \"Downloaded file from $($RemotePath) to $($LocalPath)\"\r\n                }\r\n                catch\r\n                {\r\n                    $ok=$false;\r\n                    write-host -ForegroundColor darkred \"Failed to download file from $($RemotePath) to $($LocalPath)\"\r\n                }\r\n \r\n            }\r\n        }\r\n    }\r\n }\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>A previous post covered how to programmatically download documents via FTP:\u00a0How to download from FTP programmaticallyIf FTP over SSL is needed, that\u2019s just a property to enable SSL: $request = [Net.WebRequest]::Create($url) $request.EnableSsl = $true #enable SSL Sometimes there is a need to access and download documents via SFTP. That\u2019s a completely different beast. To do [&hellip;]<\/p>\n","protected":false},"author":13,"featured_media":817,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[26,17],"tags":[],"class_list":["post-815","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-powershell","category-sharepoint-migration-services"],"acf":[],"_links":{"self":[{"href":"https:\/\/poiseddevelopers.com\/reality-tech\/wp-json\/wp\/v2\/posts\/815","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/poiseddevelopers.com\/reality-tech\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/poiseddevelopers.com\/reality-tech\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/poiseddevelopers.com\/reality-tech\/wp-json\/wp\/v2\/users\/13"}],"replies":[{"embeddable":true,"href":"https:\/\/poiseddevelopers.com\/reality-tech\/wp-json\/wp\/v2\/comments?post=815"}],"version-history":[{"count":14,"href":"https:\/\/poiseddevelopers.com\/reality-tech\/wp-json\/wp\/v2\/posts\/815\/revisions"}],"predecessor-version":[{"id":3935,"href":"https:\/\/poiseddevelopers.com\/reality-tech\/wp-json\/wp\/v2\/posts\/815\/revisions\/3935"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/poiseddevelopers.com\/reality-tech\/wp-json\/wp\/v2\/media\/817"}],"wp:attachment":[{"href":"https:\/\/poiseddevelopers.com\/reality-tech\/wp-json\/wp\/v2\/media?parent=815"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/poiseddevelopers.com\/reality-tech\/wp-json\/wp\/v2\/categories?post=815"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/poiseddevelopers.com\/reality-tech\/wp-json\/wp\/v2\/tags?post=815"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}